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;
      }
      

信息

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