4 条题解

  • 3
    @ 2025-10-13 16:30:25

    If we enumerate CC and use the KMP algorithm to calculate the minimum loop section, the complexity Θ(Tnn)\Theta (Tn \sqrt n) of the factor of the loop section length for each enumeration can be 84 points, which is sufficient for the NOIP first prize.

    But the exact solution is not difficult either. We find that when enumerating factors, many enumerations are meaningless. We are considering a different approach. Enumeration ABAB , then enumerate the number of loops, and the remaining segment is CC . For odd occurrences of characters, prefixes and techniques can be used to maintain them. The overall complexity is  Theta(nlnn)\ Theta (n\ln n) . The natural logarithm comes from harmonic series.

    #include<bits/stdc++.h>
    #define int long long
    #define uint unsigned long long
    using namespace std;
    const int N=1048577,B=131;
    int T,n,ans;
    string s;
    uint ha[N],fac[N];
    int cnt[26],suf[N];
    int pre_cnt[27];
    inline int getha(int l,int r) {
    	return ha[r]-ha[l-1]*fac[r-l+1];
    }
    signed main() {
    	std::ios::sync_with_stdio(0),cin.tie(0);
    	cin>>T;
    	while(T--) {
    		cin>>s;
    		n=s.size();
    		s=" "+s;
    		fac[0]=1,ans=0;
    		for(int i=1; i<=n; ++i) {
    			fac[i]=fac[i-1]*B;
    			ha[i]=ha[i-1]*B+s[i];
    		}
    		memset(cnt,0,sizeof cnt);
    		for(int i=n,nw=0; i>=1; --i) {
    			++cnt[s[i]-'a'];
    			if(cnt[s[i]-'a']&1)++nw;
    			else --nw;
    			suf[i]=nw;
    		}
    		memset(cnt,0,sizeof cnt);
    		memset(pre_cnt,0,sizeof pre_cnt);
    		for(int i=1,nw=0; i<=n; ++i) {
    			if(i>=2) {
    				for(int j=1; j*i<n; ++j) {
    					if(getha(1,i)==getha(1+(j-1)*i,j*i)) {
    						ans+=pre_cnt[suf[j*i+1]];
    					} else break;
    				}
    			}
    			++cnt[s[i]-'a'];
    			if(cnt[s[i]-'a']&1)++nw;
    			else --nw;
    			for(int j=0; j<=26; ++j) {
    				if(j>=nw) ++pre_cnt[j];
    			}
    		}
    		cout<<ans<<'\n';
    	}
    	return 0;
    }
    
    • @ 2025-10-13 16:32:42

      Considering that most of you have trouble in English. I plan to public a Chinese version.

      如果枚举 CC,前面用 KMP 算法计算最小循环节,每一次枚举循环节长度的因数,复杂度 Θ(Tnn)\Theta(Tn\sqrt n),可以得到 84 分,对于 NOIP 一等奖,这已经足够了。

      但是正解也不难,我们发现枚举因数时,很多枚举都是无意义的。我们考虑换一个思路。枚举 ABAB,然后枚举循环个数,最后剩下的一段就是 CC。对于奇数次出现的字符个数,可以使用前缀和技巧维护。整体复杂度 Θ(nlnn)\Theta(n\ln n)。其中自然对数来自调和级数。

      #include<bits/stdc++.h>
      #define int long long
      #define uint unsigned long long
      using namespace std;
      const int N=1048577,B=131;
      int T,n,ans;
      string s;
      uint ha[N],fac[N];
      int cnt[26],suf[N];
      int pre_cnt[27];
      inline int getha(int l,int r) {
      	return ha[r]-ha[l-1]*fac[r-l+1];
      }
      signed main() {
      	std::ios::sync_with_stdio(0),cin.tie(0);
      	cin>>T;
      	while(T--) {
      		cin>>s;
      		n=s.size();
      		s=" "+s;
      		fac[0]=1,ans=0;
      		for(int i=1; i<=n; ++i) {
      			fac[i]=fac[i-1]*B;
      			ha[i]=ha[i-1]*B+s[i];
      		}
      		memset(cnt,0,sizeof cnt);
      		for(int i=n,nw=0; i>=1; --i) {
      			++cnt[s[i]-'a'];
      			if(cnt[s[i]-'a']&1)++nw;
      			else --nw;
      			suf[i]=nw;
      		}
      		memset(cnt,0,sizeof cnt);
      		memset(pre_cnt,0,sizeof pre_cnt);
      		for(int i=1,nw=0; i<=n; ++i) {
      			if(i>=2) {
      				for(int j=1; j*i<n; ++j) {
      					if(getha(1,i)==getha(1+(j-1)*i,j*i)) {
      						ans+=pre_cnt[suf[j*i+1]];
      					} else break;
      				}
      			}
      			++cnt[s[i]-'a'];
      			if(cnt[s[i]-'a']&1)++nw;
      			else --nw;
      			for(int j=0; j<=26; ++j) {
      				if(j>=nw) ++pre_cnt[j];
      			}
      		}
      		cout<<ans<<'\n';
      	}
      	return 0;
      }
      
  • 1
    @ 2025-10-13 16:06:49

    考场上的思路是考虑枚举 CC 的长度,然后计算合法的 AABB ,然而这并不可行

    所以我们考虑枚举 ABAB 整个的长度,然后只要是循环节我们就累加答案,否则就退出

    枚举 ABAB 然后判断是否为循环节可以使用哈希完成

    然后对于出现奇数次数的字母显然可以使用桶来计算出来,然后我们需要使用一个二维数组 ai,ja_{i,j} 表示前 ii 个字符为 AA ,且出现奇数次数字母的前缀个数 j\leq j 的数量,然后就做完了

    但是可能需要卡常,不要把所有东西都开成long long,哈希使用unsigned long long

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #define P 13331
    #define uint unsigned long long
    using namespace std;
    bool Test_MLE_start;
    const int N=(1<<20)+10;
    int _=1,n,a[N][27];long long ans=0;
    short ton[30],cnt[N],suf[N];
    uint h[N],fac[N];char s[N];
    inline int reads(){
    	char c=getchar();
    	int x=0,f=1;
    	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<3)+(x<<1)+(c^'0');c=getchar();}
    	return x*f;
    }
    inline void files(){
    	freopen("string.in","r",stdin);
    	freopen("string.out","w",stdout);
    }
    inline void clr(){
    //	Don't forget!
    	ans=0;
    	for(int i=1;i<=n;i++){
    		h[i]=suf[i]=cnt[i]=0;
    		for(int j=0;j<=26;j++) a[i][j]=0,ton[j]=0;
    	}
    }
    uint get_ha(int L,int R){return h[R]-h[L-1]*fac[R-L+1];}
    bool Test_MLE_end;
    signed main(){
    //	printf("%lf Mb\n",(&Test_MLE_end-&Test_MLE_start-1)/1024.0/1024.0);
    //	files();
    	_=reads();
    	while(_--){
    		clr();scanf("%s",s+1);n=strlen(s+1);fac[0]=1;
    		for(int i=1;i<=n;i++){
    			h[i]=h[i-1]*P+s[i],fac[i]=fac[i-1]*P;
    			ton[s[i]-'a'+1]++;
    			for(int j=1;j<=26;j++){
    				if(ton[j]&1) cnt[i]++;
    			}a[i][cnt[i]]++;
    			for(int j=0;j<=26;j++) a[i][j]+=a[i-1][j];
    		}for(int i=1;i<=n;i++){
    			for(int j=1;j<=26;j++) a[i][j]+=a[i][j-1];
    		}memset(ton,0,sizeof(ton));
    		for(int i=n;i>=1;i--){
    			ton[s[i]-'a'+1]++;
    			for(int j=1;j<=26;j++){
    				if(ton[j]&1) suf[i]++;
    			}
    		}for(int len=2;len<=n;len++){
    			for(int i=len+1;i<=n;i+=len){
    				ans+=a[len-1][suf[i]];
    				if(get_ha(1,len)!=get_ha(i,i+len-1)) break;
    			}
    		}printf("%lld\n",ans);
    	}
    	return 0;
    }
    /*
    1
    mmlmmlo
    */```
    • @ 2025-10-13 17:10:00

      这是一个很刻毒的代码

      #include<iostream>
      #include<cstdio>
      #include<cstring>
      
      #define int long long
      #define uint unsigned long long
      #define N 1048577
      #define HAJIMIJINZHISHU 131
      
      using namespace std;
      
      inline int yigepingpingwuqidekuaidu(){
      	int shurujinlaideshu=0,fushudechuli=1; char shurujinlaideyuanshizifu=getchar();
      	while (shurujinlaideyuanshizifu<'0' || shurujinlaideyuanshizifu>'9'){
      		if (shurujinlaideyuanshizifu=='-') fushudechuli=-1;
      		shurujinlaideyuanshizifu=getchar();
      	} 
      	while (shurujinlaideyuanshizifu>='0'&&shurujinlaideyuanshizifu<='9'){
      		shurujinlaideshu=(shurujinlaideshu<<1)+(shurujinlaideshu<<3)+(shurujinlaideyuanshizifu^'0');
      		shurujinlaideyuanshizifu=getchar();
      	}
      	return shurujinlaideshu*fushudechuli;
      }
      
      int SHABIDUOCE,caicaizhegezifuchuanyouduochang; char zheshishurudezifuchuan[N];
      
      uint hajimi[N],hajiminanbeiluduoyongdaodejiecheng[N];
      uint Gethajimi(int chaojiniubidezuoduandian,int buxixideyouduandian){
      	return hajimi[buxixideyouduandian]-hajimi[chaojiniubidezuoduandian-1]*hajiminanbeiluduoyongdaodejiecheng[buxixideyouduandian-chaojiniubidezuoduandian+1];
      }
      
      int xiangdangyuyigetong[30],houzhuijishuzifuchuxiancishu[N],FqianzhuixiaoyuJdechuxiancishuerqiehaiyouyigeSBdegundongshuzu[30],zuizhongdedaan;
      
      signed main(){
      	hajiminanbeiluduoyongdaodejiecheng[0]=1; for (int i=1;i<=1048576;i++) hajiminanbeiluduoyongdaodejiecheng[i]=hajiminanbeiluduoyongdaodejiecheng[i-1]*HAJIMIJINZHISHU;
      	SHABIDUOCE=yigepingpingwuqidekuaidu();
      	while (SHABIDUOCE--){
      		memset(xiangdangyuyigetong,0,sizeof(xiangdangyuyigetong)); memset(FqianzhuixiaoyuJdechuxiancishuerqiehaiyouyigeSBdegundongshuzu,0,sizeof(FqianzhuixiaoyuJdechuxiancishuerqiehaiyouyigeSBdegundongshuzu)); zuizhongdedaan=0;
      		scanf(" %s",zheshishurudezifuchuan+1);caicaizhegezifuchuanyouduochang=strlen(zheshishurudezifuchuan+1);
      		for (int yicenbianli=1;yicenbianli<=caicaizhegezifuchuanyouduochang;yicenbianli++) hajimi[yicenbianli]=hajimi[yicenbianli-1]*HAJIMIJINZHISHU+zheshishurudezifuchuan[yicenbianli];
      		
      		for (int yicenbianli=caicaizhegezifuchuanyouduochang,wahningNBwoc=0;yicenbianli>=1;yicenbianli--){
      			if ((++xiangdangyuyigetong[zheshishurudezifuchuan[yicenbianli]-'a'])&1) wahningNBwoc++;
      			else wahningNBwoc--;
      			houzhuijishuzifuchuxiancishu[yicenbianli]=wahningNBwoc;
      		}memset(xiangdangyuyigetong,0,sizeof(xiangdangyuyigetong));
      		
      		for (int yicenbianli=1,wahningNBwoc=0;yicenbianli<=caicaizhegezifuchuanyouduochang;yicenbianli++){
      			if (yicenbianli>=2){
      				for (int ercenbianli=1;ercenbianli*yicenbianli<caicaizhegezifuchuanyouduochang;ercenbianli++){
      					if (Gethajimi(1,yicenbianli)==Gethajimi((ercenbianli-1)*yicenbianli+1, ercenbianli*yicenbianli)){
      						zuizhongdedaan=zuizhongdedaan+FqianzhuixiaoyuJdechuxiancishuerqiehaiyouyigeSBdegundongshuzu[houzhuijishuzifuchuxiancishu[ercenbianli*yicenbianli+1]];
      					}
      					else break;
      				}
      			}
      			if ((++xiangdangyuyigetong[zheshishurudezifuchuan[yicenbianli]-'a'])&1) wahningNBwoc++;
      			else wahningNBwoc--;
      			for (int ercenbianli=wahningNBwoc;ercenbianli<=26;ercenbianli++) ++FqianzhuixiaoyuJdechuxiancishuerqiehaiyouyigeSBdegundongshuzu[ercenbianli];
      		}
      		printf("%lld\n",zuizhongdedaan);
      	}
      	return 0;
      }
      
  • -1
    @ 2025-10-13 16:11:27

    考場上的思路是考慮枚舉CC的長度,然後計算合法的AABB,然而這並不可行 所以我們考慮枚舉ABAB整個的長度,然後只要是迴圈節我們就累加答案,否則就退出

    枚舉ABAB然後判斷是否為迴圈節可以使用雜湊完成

    然後對於出現奇數次數的字母顯然可以使用桶來計算出來,然後我們需要使用一個二維陣列aija_{i,j}表示前ii個字元為AA,且出現奇數次數字母的首碼個數j\leq j的數量,然後就做完了

    但是可能需要卡常,不要把所有東西都開成long long,雜湊使用unsigned long long

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #define P 13331
    #define uint unsigned long long
    using namespace std;
    bool Test_MLE_start;
    const int N=(1<<20)+10;
    int _=1,n,a[N][27];long long ans=0;
    short ton[30],cnt[N],suf[N];
    uint h[N],fac[N];char s[N];
    inline int reads(){
    	char c=getchar();
    	int x=0,f=1;
    	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<3)+(x<<1)+(c^'0');c=getchar();}
    	return x*f;
    }
    inline void files(){
    	freopen("string.in","r",stdin);
    	freopen("string.out","w",stdout);
    }
    inline void clr(){
    //	Don't forget!
    	ans=0;
    	for(int i=1;i<=n;i++){
    		h[i]=suf[i]=cnt[i]=0;
    		for(int j=0;j<=26;j++) a[i][j]=0,ton[j]=0;
    	}
    }
    uint get_ha(int L,int R){return h[R]-h[L-1]*fac[R-L+1];}
    bool Test_MLE_end;
    signed main(){
    //	printf("%lf Mb\n",(&Test_MLE_end-&Test_MLE_start-1)/1024.0/1024.0);
    //	files();
    	_=reads();
    	while(_--){
    		clr();scanf("%s",s+1);n=strlen(s+1);fac[0]=1;
    		for(int i=1;i<=n;i++){
    			h[i]=h[i-1]*P+s[i],fac[i]=fac[i-1]*P;
    			ton[s[i]-'a'+1]++;
    			for(int j=1;j<=26;j++){
    				if(ton[j]&1) cnt[i]++;
    			}a[i][cnt[i]]++;
    			for(int j=0;j<=26;j++) a[i][j]+=a[i-1][j];
    		}for(int i=1;i<=n;i++){
    			for(int j=1;j<=26;j++) a[i][j]+=a[i][j-1];
    		}memset(ton,0,sizeof(ton));
    		for(int i=n;i>=1;i--){
    			ton[s[i]-'a'+1]++;
    			for(int j=1;j<=26;j++){
    				if(ton[j]&1) suf[i]++;
    			}
    		}for(int len=2;len<=n;len++){
    			for(int i=len+1;i<=n;i+=len){
    				ans+=a[len-1][suf[i]];
    				if(get_ha(1,len)!=get_ha(i,i+len-1)) break;
    			}
    		}printf("%lld\n",ans);
    	}
    	return 0;
    }
    /*
    1
    mmlmmlo
    */```
    • -3
      @ 2025-10-13 16:12:42

      The idea in the exam room is to enumerate the length of CC and then calculate the valid AA and BB , but this is not feasible

      So we consider enumerating the entire length of ABAB , and then accumulating the answers as long as it is a loop section, otherwise we exit

      List ABAB and determine if it is a cyclic section that can be completed using hashing

      Then, for letters with an odd number of occurrences, buckets can be used to calculate them. We need to use a two-dimensional array ai,ja_ {i, j} to represent the first ii characters as AA and the number of prefixes j\leq j for letters with an odd number of occurrences. That's it

      But it may need to be stuck, don't open everything as' long long ', use' unsigned long long 'for hashing`

      #include<iostream>
      #include<cstring>
      #include<cstdio>
      #include<vector>
      #define P 13331
      #define uint unsigned long long
      using namespace std;
      bool Test_MLE_start;
      const int N=(1<<20)+10;
      int _=1,n,a[N][27];long long ans=0;
      short ton[30],cnt[N],suf[N];
      uint h[N],fac[N];char s[N];
      inline int reads(){
      	char c=getchar();
      	int x=0,f=1;
      	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
      	while(isdigit(c)){x=(x<<3)+(x<<1)+(c^'0');c=getchar();}
      	return x*f;
      }
      inline void files(){
      	freopen("string.in","r",stdin);
      	freopen("string.out","w",stdout);
      }
      inline void clr(){
      //	Don't forget!
      	ans=0;
      	for(int i=1;i<=n;i++){
      		h[i]=suf[i]=cnt[i]=0;
      		for(int j=0;j<=26;j++) a[i][j]=0,ton[j]=0;
      	}
      }
      uint get_ha(int L,int R){return h[R]-h[L-1]*fac[R-L+1];}
      bool Test_MLE_end;
      signed main(){
      //	printf("%lf Mb\n",(&Test_MLE_end-&Test_MLE_start-1)/1024.0/1024.0);
      //	files();
      	_=reads();
      	while(_--){
      		clr();scanf("%s",s+1);n=strlen(s+1);fac[0]=1;
      		for(int i=1;i<=n;i++){
      			h[i]=h[i-1]*P+s[i],fac[i]=fac[i-1]*P;
      			ton[s[i]-'a'+1]++;
      			for(int j=1;j<=26;j++){
      				if(ton[j]&1) cnt[i]++;
      			}a[i][cnt[i]]++;
      			for(int j=0;j<=26;j++) a[i][j]+=a[i-1][j];
      		}for(int i=1;i<=n;i++){
      			for(int j=1;j<=26;j++) a[i][j]+=a[i][j-1];
      		}memset(ton,0,sizeof(ton));
      		for(int i=n;i>=1;i--){
      			ton[s[i]-'a'+1]++;
      			for(int j=1;j<=26;j++){
      				if(ton[j]&1) suf[i]++;
      			}
      		}for(int len=2;len<=n;len++){
      			for(int i=len+1;i<=n;i+=len){
      				ans+=a[len-1][suf[i]];
      				if(get_ha(1,len)!=get_ha(i,i+len-1)) break;
      			}
      		}printf("%lld\n",ans);
      	}
      	return 0;
      }
      /*
      1
      mmlmmlo
      */```
      • 1

      信息

      ID
      467
      时间
      1000ms
      内存
      256MiB
      难度
      10
      标签
      (无)
      递交数
      7
      已通过
      4
      上传者