• 联考 20200523 T2 蓝超巨星






    分析:
    (一道破题调一天)
    我们把A操作和B操作分开考虑
    不看字符的变化,A操作会产生(N=n/gcd(n,a))种字符串
    不看字符的位移,B操作会产生(M)种字符串
    其中(M)为所有字符通过操作形成的种类数,最坏情况为(M=4*9*5*7=1260)
    枚举种类(q(0 leq q < M)),哈希判断字符串的位移次数(p)
    (复杂度是(O(NM))的,应该不是那么容易卡掉
    那么设最终操作次数为(x)
    列出同余方程:

    (x equiv p(mod N))
    (x equiv q(mod M))

    于是开始解方程,一定注意这里是不互质的!

    (x=Nx_1+p=Mx_2+q~~~~~~~~~~(1))
    (Nx_1 equiv q-p(mod M))

    (d=gcd(N,M)),所以:

    (frac{N}{d}x_1 equiv frac{q-p}{d}(mod frac{M}{d}))

    (X=frac{c}{d}(frac{N}{d})^{-1})

    (x_1 equiv X(mod frac{M}{d}))
    (x_1=frac{M}{d}y+X)

    将(1)式代入:

    (x=frac{NM}{d}y+NX+p)
    (x equiv NX+p(mod frac{NM}{d}))

    代码就实现这个过程就好了

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<iostream>
    #include<map>
    #include<string>
    
    #define maxn 400005
    #define INF 0x3f3f3f3f
    #define base 29
    
    using namespace std;
    
    inline long long getint()
    {
    	long long num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n,m=1,A,B;
    char s[maxn],t[maxn];
    int a[maxn],b[maxn],c[maxn],sz[maxn];
    int S[maxn],T[maxn];
    long long HS,hs[maxn],pw=1;
    long long ans=-1;
    
    inline int gcd(int p,int q)
    {return q?gcd(q,p%q):p;}
    inline int lcm(int p,int q)
    {return p*q/gcd(p,q);}
    inline long long exgcd(long long p,long long q,long long &x,long long &y)
    {
    	if(!q){x=1,y=0;return p;}
    	long long num=exgcd(q,p%q,x,y);
    	long long t=x;x=y,y=t-p/q*y;
    	return num;
    }
    
    inline long long getans(long long p,long long q)
    {
    	long long N=n/gcd(n,A),M=m;
    	long long d=gcd(N,M),c=q-p,k1,k2;
    	exgcd(N,M,k1,k2);
    	if(c%d)return -1;
    	long long X=c/d*k1,t=M/d;
    	X=(X%t+t)%t;
    	X=p+N*X;
    	if(X<=0)X+=lcm(N,M);
    	return X;
    }
    
    inline void solve(int num)
    {
    	for(int i=1;i<=n;i++)S[i+n]=S[i];
    	for(int i=1;i<=2*n;i++)hs[i]=hs[i-1]*base+S[i];
    	int blk=gcd(n,A);
    	for(int i=n;i<2*n;i+=blk)
    		if(hs[i]-hs[i-n]*pw==HS)
    		{
    			long long tmp=getans(a[i%n],num);
    			if(!~ans||(tmp!=-1&&tmp<ans))ans=tmp;
    		}
    }
    
    int main()
    {
    	//freopen("blue.in","r",stdin);
    	//freopen("blue.out","w",stdout);
    	
    	n=getint(),A=getint()%n,B=getint();
    	for(int i=1,now=A;now;i++,now=(now+A)%n)a[now]=i;
    	scanf("%s",s+1);
    	for(int i=1;i<=26;i++)b[i]=s[i]-96;
    	for(int i=1;i<=26;i++){int tmp=i;do{tmp=b[tmp],sz[i]++;}while(tmp!=i);}
    	for(int i=1;i<=26;i++)
    	{
    		int tmp=B%sz[i],x=i;
    		while(tmp--)x=b[x];c[i]=x;
    	}
    	for(int i=1;i<=26;i++)b[i]=c[i],sz[i]=0;
    	for(int i=1;i<=26;i++){int tmp=i;do{tmp=b[tmp],sz[i]++;}while(tmp!=i);}
    	for(int i=1;i<=26;i++)m=lcm(m,sz[i]);
    	scanf("%s",s+1);
    	for(int i=1;i<=n;i++)S[i]=s[i]-96,pw=pw*base;
    	scanf("%s",t+1);
    	for(int i=1;i<=n;i++)T[i]=t[i]-96,HS=HS*base+T[i];
    	for(int t=0;t<m;t++)
    	{
    		solve(t);
    		for(int i=1;i<=n;i++)S[i]=b[S[i]];
    	}
    	printf("%lld
    ",ans);
    }
    

  • 相关阅读:
    数据结构-循环队列程序演示
    C++进阶:新人易入的那些坑 --1.常量、常指针和指针常量
    this.$confirm的用法
    属性或方法“degreeList”不是在实例上定义的,而是在渲染期间引用的。通过初始化该属性,确保该属性是反应性的,无论是在data选项中,还是在基于类的组件中
    CSS清除浮动
    react里的高阶组件
    map和forEach的区别
    hash和history两种模式的区别
    js原型链的理解
    for..in,for..of 和forEach的区别
  • 原文地址:https://www.cnblogs.com/Darknesses/p/12957438.html
Copyright © 2020-2023  润新知