1. 程式人生 > >【xsy1058】 單詞 亂搞

【xsy1058】 單詞 亂搞

++ efi 亂搞 個數 測試 暴力 情況 can col

題目大意:給你$n$個長度為$m$的字符串,字符集僅為{x,y,z}三個字符,定義兩個字符串$(s_i,s_j)$的相似度為$\sum_{k=1}^{m} [s_i[k]==s_j[k]]$。

從$0$到$m$詢問你相似度為i的字符串的對數。

數據範圍:$n\times m≤100000$(沒錯是乘號)

此題的題解做法貌似是:分$m≤12$和$m>12$來做。

先考慮$m≥12$的,考慮直接暴力判斷,復雜度就是$O(mn^2)$的,顯然是可以過的

當$m≤12$時,我們做一個$dp$,令$f[i][j]$表示前$i$個字符串中,字符串為$j$的個數。

考慮到字符集的大小,字符串的數量顯然是$3^m$的

時間復雜度:$O(n\times 3^{m})$。

然而,這題的時限是3s,經過測試,我們發現當$m>2$時,都可以在$3s$內跑完。

所以我們只需要特殊處理下$m=1$和$m=2$的情況就可以了。

代碼短了很多qwq

(所以字符集是不是可以出大一些了呢)

 1 #include<bits/stdc++.h>
 2 #define M 100005
 3 #define L long long
 4 #define S(x) x*(x-1)/2
 5 using namespace std;
 6 char *c[M]={0};
 7 int
n,m; L ans[M]={0}; 8 9 void solve1(){ 10 L cnt1=0,cnt2=0,cnt3=0; 11 for(int i=1;i<=n;i++){ 12 if(c[i][0]==x) cnt1++; 13 if(c[i][0]==y) cnt2++; 14 if(c[i][0]==z) cnt3++; 15 } 16 ans[1]=S(cnt1)+S(cnt2)+S(cnt3); 17 ans[0]=cnt1*cnt2+cnt1*cnt3+cnt2*cnt3;
18 } 19 void solve2(){ 20 L cnt[3][3]={0}; 21 for(int i=1;i<=n;i++){ 22 int l,r; 23 if(c[i][0]==x) l=0; 24 if(c[i][0]==y) l=1; 25 if(c[i][0]==z) l=2; 26 if(c[i][1]==x) r=0; 27 if(c[i][1]==y) r=1; 28 if(c[i][1]==z) r=2; 29 cnt[l][r]++; 30 } 31 for(int i=0;i<3;i++) for(int j=0;j<3;j++){ 32 ans[2]+=S(cnt[i][j]); 33 for(int ii=0;ii<3;ii++) for(int jj=0;jj<3;jj++){ 34 int hh=(i==ii)+(j==jj); if(hh==2) continue; 35 ans[hh]+=cnt[i][j]*cnt[ii][jj]; 36 } 37 } 38 ans[0]/=2; ans[1]/=2; 39 } 40 void solve3(){ 41 for(int i=1;i<=n;i++) 42 for(int j=i+1;j<=n;j++){ 43 int cnt=0; 44 for(int k=0;k<m;k++) cnt+=(c[i][k]==c[j][k]); 45 ans[cnt]++; 46 } 47 } 48 49 50 int main(){ 51 scanf("%d%d",&n,&m); 52 for(int i=1;i<=n;i++){ 53 c[i]=new char[m]; 54 scanf("%s",c[i]); 55 } 56 if(m==1) solve1(); 57 if(m==2) solve2(); 58 if(m>=3) solve3(); 59 for(int i=0;i<=m;i++) printf("%lld\n",ans[i]); 60 }

【xsy1058】 單詞 亂搞