http://codeforces.com/problemset/problem/526/D
题意
给定一个串 T,对它的每一个前缀能否写成 A+B+A+B+...+B+A+B+A+B+...+B+A 的形式(k +1个 A,k 个 B,均可为空串)
分析
官方题解
对于前缀P,我们可以把它拆成P=SSSS…SSSST,其中T是S的前缀。显然可以用KMP算法,时间复杂度是O(n)。
当T=S:P=SSS…S。假设S出现了R次。如果转换为ABABAB…ABABA的形式,A和B是由几个S组成,而且最后的A一定是P的一个后缀。由贪心算法,A的长度尽量小,所以A中S出现R mod Q次。B中S出现R/Q-R mod Q次。因为只需判断R/Q-R mod Q>=0即可
当T!=S:由于上一种方法类似,A可以是SSS…ST,因为它的长度尽量小,所以我们只需判断是否R/Q-R mod Q>0。
那为什么A中有R mod Q个S,B中有R/Q-R mod Q 个S?因为要将字符串P=SSSSSSS变成ABABABABA的形式,可以看成是Q份AB和一份A结合,那么每份AB就有R/Q个S,所以剩下的R%Q就是A的S,于是B就是R/Q-R mod Q了。
当T=S时,B可以为空串,也就是B的长度可以为0,于是取等号。当T!=S时,反之。
#include<iostream> #include<cmath> #include<cstring> #include<queue> #include<vector> #include<cstdio> #include<algorithm> #include<map> #include<set> #define rep(i,e) for(int i=0;i<(e);i++) #define rep1(i,e) for(int i=1;i<=(e);i++) #define repx(i,x,e) for(int i=(x);i<=(e);i++) #define X first #define Y second #define PB push_back #define MP make_pair #define mset(var,val) memset(var,val,sizeof(var)) #define scd(a) scanf("%d",&a) #define scdd(a,b) scanf("%d%d",&a,&b) #define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c) #define pd(a) printf("%d\n",a) #define scl(a) scanf("%lld",&a) #define scll(a,b) scanf("%lld%lld",&a,&b) #define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c) #define IOS ios::sync_with_stdio(false);cin.tie(0) using namespace std; typedef long long ll; template <class T> void test(T a){cout<<a<<endl;} template <class T,class T2> void test(T a,T2 b){cout<<a<<" "<<b<<endl;} template <class T,class T2,class T3> void test(T a,T2 b,T3 c){cout<<a<<" "<<b<<" "<<c<<endl;} const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f3fll; const ll mod = 200907; int T; void testcase(){ printf("Case #%d: ",++T); } const int MAXN = 1e6+5; const int MAXM = 30; int n,k; char s[MAXN]; int Next[MAXN]; void getNext(){ int i,j; j=Next[0]=-1; i=0; while(i<n){ while(-1!=j&&s[i]!=s[j]) j=Next[j]; Next[++i]=++j; } } int check(int i){ int d=i-Next[i]; //最小循环节 int cnt = i/d; //循环节次数 if(i%d==0){ //被整除 return cnt/k-cnt%k>=0; // }else return cnt/k-cnt%k>0; } int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif // LOCAL scdd(n,k); scanf("%s",s); mset(Next,0); getNext(); for(int i=1;i<=n;i++){ printf("%d",check(i)); } // for(int i=0;i<=1+n;i++) printf("%d ",Next[i]); return 0; }
原文地址:https://www.cnblogs.com/fht-litost/p/9296893.html
时间: 2024-10-28 03:43:02