zoukankan      html  css  js  c++  java
  • JZOJ1898. 【2010集训队出题】密码系统

    Description

    • Lambda受任于某情报站,他的工作是获取敌人情报。一次他在破解密码系统时,得到了一个N位B进制数φ,满足φ≡V (mod M)。他发现组成φ的数字很奇特。为了验证φ的特殊性,他将所有模M为V的N位B进制数,按照各数位构成的集合分类,并想知道每一类数各有多少个。
      在这里插入图片描述

    Solution

    • 不难想到矩乘,枚举所选集合再进行矩乘,f[i]表示余数为i的方案数,但是这样并不能保证集合中的都被选了,所以实际算出来需要容斥一下。
    • 再考虑矩乘的复杂度,如果直接M3是会爆的。但是我们发现将i和j合并起来时转移到的状态是一定的并且可以算出来,所以M2转移就好了。
    • 为什么这题这么特殊呢?
    • 我们一般的矩乘要枚举起点终点,而这题却枚举起点和终点间的转移,并且显然转移比那个枚举地更少更好。所以说这种情况仅当转移状态十分好枚举地时候才适用。
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define maxm 125
    #define mo 10007
    using namespace std;
    
    int n,B,M,V,S,T,i,j,k,p;
    int f[maxm],ff[maxm],g[maxm],gg[maxm];
    int F[1<<11];
    
    int main(){
    	scanf("%d%d%d%d",&n,&B,&M,&V);
    	for(S=1;S<1<<B;S++){
    		memset(f,0,sizeof(f));
    		memset(g,0,sizeof(g));
    		for(i=0;i<B;i++) if ((S>>i)&1) g[i%M]++;
    		for(i=1;i<B;i++) if ((S>>i)&1) f[i%M]++;
    		p=B%M;
    		for(k=n-1;k;k/=2){
    			if (k&1){
    				memset(ff,0,sizeof(ff));
    				for(i=0;i<M;i++) if (f[i]) for(j=0;j<M;j++) if (g[j])
    					(ff[(i*p+j)%M]+=f[i]*g[j])%=mo;
    				memcpy(f,ff,sizeof(ff));
    			}
    			memset(gg,0,sizeof(gg));
    			for(i=0;i<M;i++) if (g[i]) for(j=0;j<M;j++) if (g[j])
    				(gg[(i*p+j)%M]+=g[i]*g[j]%mo)%=mo;
    			memcpy(g,gg,sizeof(gg));
    			p=p*p%M;
    		}
    		F[S]=f[V];
    		for(T=0;T<S;T++) if ((T&S)==T) 
    			F[S]=(F[S]-F[T]+mo)%mo;
    		for(i=B-1;i>=0;i--) if ((S>>i)&1) printf("%d",i);
    		printf(" %d
    ",F[S]);
    	}
    }
    
  • 相关阅读:
    [模板] 文艺平衡树
    [模板]平衡树splay
    [ZJOI2015]诸神眷顾的幻想乡
    [HAOI2016]找相同字符
    SP8093 JZPGYZ
    SP1812 LCS2
    SP1811 LCS
    AHOI2013 差异
    TJOI2015 弦论
    工艺(SAM)
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/11700909.html
Copyright © 2011-2022 走看看