求過審
題面翻譯
給定一個字串 $ s $ ,求執行以下操作一次可以產生的字串的個數
設 $ N $ 為 $ s $ 的長度。選擇一對整數 $ (i,j) $ ,使 $ 1≤i<j≤N $ ,交換 $ s $ 的第 $ i $ 個和第 $ j $ 個字元
可以證明,在這個問題的約束條件下,你總是可以得到它
思路
暴力做法
我們可以暴力列舉 $ 1 \leq i < j \leq N $
若 $ s_i=s_j $ ,即交換後 $ s $ 不變,那麼跳過
否則 $ ans $ 加 $ 1 $
注意:如果有重複字母,需要將 $ ans $ 加 $ 1 $
#include<bits/stdc++.h>
#define ll long long
using namespace std;
string s;
ll l,ans=0,f=0;
int main()
{
ios::sync_with_stdio(0);//關閉流同步
cin>>s;
l=s.size();
s=' '+s;//巧妙地把第一位下標轉成1
for(int i=1;i<=l;i++)
{
for(int j=i+1;j<=l;j++)
{
if(s[i]!=s[j]) ans++;
else f=1;
}
}
cout<<ans+f;
return 0;
}
提交後發現 $ TLE\ 13 $ 個點
最佳化
我們可以發現對於 $ s_i $
那麼和其相等的 $ s_j $ 的個數可以透過字尾和統計
於是
for(int j=i+1;j<=l;j++)
{
if(s[i]!=s[j]) ans++;
else f=1;
}
這重迴圈可以變為
ans+=l-i+1sum[s[i]-'a'+1];
//這裡是把a的下標看做1
//sum是字尾和
所以我們可以先求字尾和,然後計算
也可以倒著列舉,邊計算邊求
這裡採用倒著列舉:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
string s;
ll f[1000100],a[100100],l,fl;
//fl記錄是否有重複字母
int main()
{
cin>>s;
l=s.size();
s=' '+s;
a[s[l]-'a'+1]=1;
f[l]=0;
for(ll i=l-1;i>=1;--i)
{
a[s[i]-'a'+1]++;
if(!fl&&a[s[i]-'a'+1]>1) fl=1;
f[i]=l-i+1-a[s[i]-'a'+1];
}
for(ll i=1;i<=l;++i) f[0]+=f[i];
cout<<f[0]+fl;
return 0;
}
無關的話(稽核大大不要計較):被禁言了,怎麼解啊?
感謝觀看