bzoj2032 [国家集训队]密码系统
题意
对于所有的 N N N 位 B B B 进制数 φ φ φ,按照各数位构成的集合分类,求每一类各有多少个数满足 φ ≡ V (     m o d M ) φ≡V (\!\!\!\!\mod M) φ≡V(modM),答案对 1000 1000 1000。
数据范围:
对于 60 % 60\% 60% 的数据, B ⩽ 3 B\leqslant 3 B⩽3, M ⩽ 120 M\leqslant 120 M⩽120;
对于另外 40 % 40\% 40% 的数据, B ⩽ 10 B\leqslant 10 B⩽10, M ⩽ 40 M\leqslant 40 M⩽40;
对于 100 % 100\% 100% 的数据, N ⩽ 1 0 9 N\leqslant 10^9 N⩽109, V ⩽ M V\leqslant M V⩽M。
解析
看见 
    
     
      
       
        N
       
       
        ⩽
       
       
        1
       
       
        
         0
        
        
         9
        
       
      
      
       N\leqslant 10^9
      
     
    N⩽109,果断考虑数论或者矩阵快速幂优化DP,考虑到每个数位直接联系不大,应该为矩阵快速幂。
 设 
    
     
      
       
        
         f
        
        
         
          i
         
         
          ,
         
         
          j
         
         
          ,
         
         
          S
         
        
       
      
      
       f_{i,j,S}
      
     
    fi,j,S 表示递推到第 
    
     
      
       
        i
       
      
      
       i
      
     
    i 位,余数为 
    
     
      
       
        j
       
      
      
       j
      
     
    j,使用的数位状态为 
    
     
      
       
        S
       
      
      
       S
      
     
    S 时的方案数,如 
    
     
      
       
        
         f
        
        
         
          2
         
         
          ,
         
         
          1
         
         
          ,
         
         
          (
         
         
          101
         
         
          
           )
          
          
           2
          
         
        
       
      
      
       f_{2,1,(101)_2}
      
     
    f2,1,(101)2 表示递推到了第 
    
     
      
       
        2
       
      
      
       2
      
     
    2 位,余数为 
    
     
      
       
        1
       
      
      
       1
      
     
    1,使用了 
    
     
      
       
        0
       
      
      
       0
      
     
    0 和 
    
     
      
       
        2
       
      
      
       2
      
     
    2 两个数字的方案数。
 设下一位填入的数为 
    
     
      
       
        d
       
       
        (
       
       
        0
       
       
        ⩽
       
       
        d
       
       
        <
       
       
        b
       
       
        )
       
      
      
       d(0\leqslant d<b)
      
     
    d(0⩽d<b),可得:
 
    
     
      
       
        
         f
        
        
         
          i
         
         
          ,
         
         
          j
         
         
          ,
         
         
          S
         
        
       
       
        =
       
       
        
         ∑
        
        
         
          b
         
         
          k
         
         
          +
         
         
          d
         
         
          ≡
         
         
          j
         
         
          (
             
         
         
         
          
           m
          
          
           o
          
          
           d
          
           
         
          M
         
         
          )
         
         
          ,
         
         
          
           S
          
          
           ′
          
         
         
          ∪
         
         
          {
         
         
          j
         
         
          }
         
         
          =
         
         
          S
         
        
       
       
        
         f
        
        
         
          i
         
         
          −
         
         
          1
         
         
          ,
         
         
          k
         
         
          ,
         
         
          
           S
          
          
           ′
          
         
        
       
      
      
       f_{i,j,S}=\sum\limits_{bk+d≡j (\!\!\!\!\mod M),S'\cup \{j\}=S} f_{i-1,k,S'}
      
     
    fi,j,S=bk+d≡j(modM),S′∪{j}=S∑fi−1,k,S′
 对 
    
     
      
       
        i
       
      
      
       i
      
     
    i 进行优化,建立一个大小为 
    
     
      
       
        M
       
       
        
         2
        
        
         B
        
       
      
      
       M2^B
      
     
    M2B 的矩阵加速递推,时间复杂度为 
    
     
      
       
        O
       
       
        (
       
       
        
         8
        
        
         B
        
       
       
        
         M
        
        
         3
        
       
       
        l
       
       
        o
       
       
        g
       
       
        N
       
       
        )
       
      
      
       O(8^BM^3logN)
      
     
    O(8BM3logN),无法通过。
 时间复杂度的瓶颈在于过于巨大的矩阵大小,可以看到这个 
    
     
      
       
        
         2
        
        
         B
        
       
      
      
       2^B
      
     
    2B 过于恶臭,考虑优化它。
对于一个状态 
    
     
      
       
        S
       
      
      
       S
      
     
    S,可以发现它要求每个数位至少存在一次,所以占据了巨大的空间。
 如果改为求出一个状态 
    
     
      
       
        S
       
      
      
       S
      
     
    S 的所有子集,那么方程中的 
    
     
      
       
        
         S
        
        
         ′
        
       
      
      
       S'
      
     
    S′ 就会等于 
    
     
      
       
        S
       
      
      
       S
      
     
    S,我们就可以省下这一大部分的矩阵大小。
 具体的,从小到大枚举 
    
     
      
       
        S
       
      
      
       S
      
     
    S,设 
    
     
      
       
        
         f
        
        
         
          i
         
         
          ,
         
         
          j
         
        
       
      
      
       f_{i,j}
      
     
    fi,j 表示递推到 
    
     
      
       
        i
       
      
      
       i
      
     
    i 为,余数为 
    
     
      
       
        j
       
      
      
       j
      
     
    j 时的方案数。可得:
 
    
     
      
       
        
         f
        
        
         
          i
         
         
          ,
         
         
          j
         
        
       
       
        =
       
       
        
         ∑
        
        
         
          b
         
         
          k
         
         
          +
         
         
          d
         
         
          ≡
         
         
          j
         
         
          (
             
         
         
         
          
           m
          
          
           o
          
          
           d
          
           
         
          M
         
         
          )
         
        
       
       
        
         f
        
        
         
          i
         
         
          −
         
         
          1
         
         
          ,
         
         
          k
         
        
       
      
      
       f_{i,j}=\sum\limits_{bk+d≡j (\!\!\!\!\mod M)} f_{i-1,k}
      
     
    fi,j=bk+d≡j(modM)∑fi−1,k
 目标状态为 
    
     
      
       
        
         f
        
        
         
          n
         
         
          −
         
         
          1
         
         
          ,
         
         
          V
         
        
       
      
      
       f_{n-1,V}
      
     
    fn−1,V,最后不可以填 
    
     
      
       
        0
       
      
      
       0
      
     
    0,需特殊考虑。
 对于每个 
    
     
      
       
        S
       
      
      
       S
      
     
    S 具体的状态,直接枚举子集容斥掉即可求出。
 时间复杂度为 
    
     
      
       
        O
       
       
        (
       
       
        
         2
        
        
         B
        
       
       
        
         M
        
        
         3
        
       
       
        l
       
       
        o
       
       
        g
       
       
        N
       
       
        +
       
       
        
         3
        
        
         B
        
       
       
        )
       
      
      
       O(2^BM^3logN+3^B)
      
     
    O(2BM3logN+3B),还是不太行。
既然矩阵行不通,那就不使用矩阵,用另外的方式来进行递推。
 观察之前的转移,每次一点一点的转移非常的缓慢,能不能多走几步呢?
 可以。依然沿用先前 
    
     
      
       
        
         f
        
        
         
          i
         
         
          ,
         
         
          j
         
        
       
      
      
       f_{i,j}
      
     
    fi,j 的定义,可得递推:
 
    
     
      
       
        
         f
        
        
         
          i
         
         
          ,
         
         
          j
         
        
       
       
        =
       
       
        
         ∑
        
        
         
          
           j
          
          
           1
          
         
         
          
           b
          
          
           
            i
           
           
            2
           
          
         
         
          +
         
         
          
           j
          
          
           2
          
         
         
          ≡
         
         
          j
         
         
          (
             
         
         
         
          
           m
          
          
           o
          
          
           d
          
           
         
          M
         
         
          )
         
        
       
       
        
         f
        
        
         
          
           i
          
          
           1
          
         
         
          ,
         
         
          
           j
          
          
           1
          
         
        
       
       
        
         f
        
        
         
          
           i
          
          
           2
          
         
         
          ,
         
         
          
           j
          
          
           2
          
         
        
       
      
      
       f_{i,j}=\sum\limits_{j_1b^{i_2}+j_2≡j (\!\!\!\!\mod M)}f_{i_1,j_1}f_{i_2,j_2}
      
     
    fi,j=j1bi2+j2≡j(modM)∑fi1,j1fi2,j2
 其中 
    
     
      
       
        
         i
        
        
         1
        
       
       
        +
       
       
        
         i
        
        
         2
        
       
       
        =
       
       
        i
       
      
      
       i_1+i_2=i
      
     
    i1+i2=i,不做硬性要求。
 那么可以沿用快速幂的思想,用多个 
    
     
      
       
        
         f
        
        
         
          
           2
          
          
           i
          
         
         
          ,
         
         
          x
         
        
       
      
      
       f_{2^i,x}
      
     
    f2i,x 来拼凑出 
    
     
      
       
        
         f
        
        
         
          n
         
         
          −
         
         
          1
         
         
          ,
         
         
          V
         
        
       
      
      
       f_{n-1,V}
      
     
    fn−1,V。
 那么一次合并的时间复杂度为 
    
     
      
       
        O
       
       
        (
       
       
        
         M
        
        
         2
        
       
       
        )
       
      
      
       O(M^2)
      
     
    O(M2),总时间复杂度即为 
    
     
      
       
        O
       
       
        (
       
       
        
         2
        
        
         B
        
       
       
        
         M
        
        
         2
        
       
       
        l
       
       
        o
       
       
        g
       
       
        N
       
       
        +
       
       
        
         3
        
        
         B
        
       
       
        )
       
      
      
       O(2^BM^2logN+3^B)
      
     
    O(2BM2logN+3B),可以通过。
Code
#include<bits/stdc++.h>
#define mod 10007
using namespace std;
int n,b,m,V;
int dp[130],t[130],_dp[130],_ans[1024],ans[1024];
int main()
{
	cin>>n>>b>>m>>V;
	n--;
	for(int i=1;i<(1<<b);i++)
	{
		memset(t,0,sizeof t);
		memset(dp,0,sizeof dp);
		for(int j=0;j<b;j++)
			if(i&(1<<j))
			{
				t[j%m]++;
				if(j!=0)dp[j%m]++;
			}
		for(int j=n,x=b%m;j;j>>=1,x=(x*x)%m)
		{
			if(j&1)
			{
				memset(_dp,0,sizeof _dp);
				for(int u=0;u<m;u++)
					for(int v=0;v<m;v++)
						_dp[(u*x+v)%m]=(_dp[(u*x+v)%m]+dp[u]*t[v])%mod;
				memcpy(dp,_dp,sizeof _dp);
			}
			memset(_dp,0,sizeof _dp);
			for(int u=0;u<m;u++)
				for(int v=0;v<m;v++)
					_dp[(u*x+v)%m]=(_dp[(u*x+v)%m]+t[u]*t[v])%mod;
			memcpy(t,_dp,sizeof _dp);
		}
		ans[i]=dp[V];
		for(int j=i&(i-1);j;j=(j-1)&i)
			ans[i]=(ans[i]-ans[j]+mod)%mod;
		for(int j=b-1;j>=0;j--)
			if(i&(1<<j))cout<<j;
		cout<<' '<<ans[i]<<'\n';
	}
}
 
总结
一个很神奇的题,从容斥的应用到矩阵的优化成递推都是非常精妙的优化,难得一见的好题。

                
            
        
浙公网安备 33010602011771号