zoukankan      html  css  js  c++  java
  • 2020-2021 “Orz Panda” Cup Programming Contest E. Encryption of Orz Pandas(生成函数,FFT)

    https://codeforces.com/gym/102870
    题意:

    给定数组a,定义一次操作为对a求异或前缀和数组,求出的数组作为新的a。求a进行k次操作后的值

    (n<=1e5,a_i<=2^{17},k<=1e18)

    解法:

    找规律可以发现,不停进行求前缀和操作,a的值会循环变化,循环节是>=n的最小2的幂次,这样就可以将k减小至1e5的级别。

    异或操作对于不同数位之间是没有影响的,因此可以将a数组的各数位分离,对于一个数位的数组进行求异或前缀和,就相当于求前缀和最后模2。而对一个长度为n+1的数组求前缀和,可以转化为生成函数来考虑,相当于乘一个生成函数((1+x+x^2+...+x^n)),题目要求做k次操作,则相当于对原数组乘一个((1+x+x^2+...+x^n)^k),后者可以用FFT套快速幂快速求出,因为最后答案只要取前n+1位,每次多项式相乘只要保留前n+1位即可。

    #include<bits/stdc++.h>
    typedef long long ll;
    typedef double db;
    using namespace std;
    const db pi=acos(-1.0);
    struct cp{
    	db x,y;
    	cp(){x=y=0;}
    	cp(db xx,db yy){x=xx,y=yy;}
    };
    cp operator + (cp a,cp b){
    	return cp(a.x+b.x,a.y+b.y);
    }cp operator - (cp a,cp b){
    	return cp(a.x-b.x,a.y-b.y);
    }cp operator * (cp a,cp b){
    	return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
    }
    inline void FFT(int n,vector<cp> &a,int t,vector<int> &rev){//迭代版FFT
    	for(int i=0;i<=n-1;i++)
    		if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int len=1;len<=(n>>1);len<<=1){
    		cp w1(cos(pi/len),t*sin(pi/len));
    		for(int i=0;i<=n-(len<<1);i+=(len<<1)){
    			cp w(1,0);
    			for(int j=0;j<=len-1;j++){
    				cp x=a[i+j],y=w*a[i+j+len];
    				a[i+j]=x+y,a[i+j+len]=x-y;
    				w=w*w1;
    			}
    		}
    	}
    }
    void solve(vector<int>&a,vector<int>&b,vector<int>&res){
        int n,m;
    	n=a.size()-1,m=b.size()-1;
    	int k=1,ci=0;
    	while(k<=n+m)k<<=1,ci++;
    	vector<int> rev(k+1,0);
    	vector<cp> f(k+1),g(k+1);
    	for(int i=0;i<=n;i++)f[i].x=a[i];
    	for(int i=0;i<=m;i++)g[i].x=b[i];
    	for(int i=1;i<=k-1;i++)//二进制翻转
    		rev[i]=(rev[i>>1]>>1)|((i&1)<<(ci-1));
    	FFT(k,f,1,rev);
    	FFT(k,g,1,rev);
    	for(int i=0;i<=k;i++)
    		f[i]=f[i]*g[i];
    	FFT(k,f,-1,rev);
    	res.resize(n+m+1);
    	for(int i=0;i<=n+m;i++)
            res[i]=((int)(f[i].x/k+0.5))&1;
    }
    void m2(vector<int>&a){
        int n,m;
    	n=m=a.size()-1;
    	int k=1,ci=0;
    	while(k<=n+m)k<<=1,ci++;
    	vector<int> rev(k+1,0);
    	vector<cp> f(k+1);
    	for(int i=0;i<=n;i++)f[i].x=a[i];
    	for(int i=1;i<=k-1;i++)//二进制翻转
    		rev[i]=(rev[i>>1]>>1)|((i&1)<<(ci-1));
    	FFT(k,f,1,rev);
    	for(int i=0;i<=k;i++)
    		f[i]=f[i]*f[i];
    	FFT(k,f,-1,rev);
    	for(int i=0;i<=n;i++)
            a[i]=((int)(f[i].x/k+0.5))&1;
    }
    vector<int> ksm(vector<int> a,ll p){
        vector<int>ans={1};
        int sz=a.size();
        while(p){
            if(p&1){
                solve(ans,a,ans);
                ans.resize(sz);
            }
            m2(a);
            p>>=1;
        }
        return ans;
    }
    int main(){
        int n;
        ll k;
        scanf("%d%lld",&n,&k);
        n--;
        int ci=1;
        while(ci<n+1)ci<<=1;
        k%=ci;
        vector<int> a(n+1),ans(n+1);
        for(int i=0;i<=n;i++){
            scanf("%d",&a[i]);
        }
        vector<int> c(n+1);
        for(int i=0;i<=n;i++)c[i]=1;
        c=ksm(c,k);
        for(int p=1;p<=17;p++){
            vector<int> b(n+1);
            for(int i=0;i<=n;i++){
                b[i]=a[i]&1;
                a[i]>>=1;
            }
            vector<int> res;
            solve(b,c,res);
            for(auto &x:res)x&=1;
            for(int i=0;i<=n;i++){
                if(res[i])
                    ans[i]|=(1<<(p-1));
            }
        }
        for(int i=0;i<=n;i++){
            if(i>0)printf(" ");
            printf("%d",ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    浅析椭圆曲线加密算法(ECC)
    比特币原理——交易与UTXO
    比特币白皮书-学习笔记
    python SMTP邮件发送
    Linux : Forks()
    IS: [=Burp Suite No.4=]Burp Suite /Scanner/ and /Intruder/
    IS: [=Burp Suite No.3=]Burp Suite /Target/ and /Spider/
    IS: [=Burp Suite No.2=]Burp Suite SSL and advanced options
    IS: [=Burp Suite No.1=]Burp Suite install and configuration
    IS: WMIC command use
  • 原文地址:https://www.cnblogs.com/ucprer/p/14396462.html
Copyright © 2011-2022 走看看