[HNOI2011]卡农
卡农
题解
我们可以发现,一个合法的序列应当满足下面 3 3 3个条件:
- 没有空集的存在。
- 所有集合都不会重复出现。
- 每个音阶的出现次数为偶。
由于要保证每个音阶的出现次数为偶,所以当选择的前 
     
      
       
       
         m 
        
       
         − 
        
       
         1 
        
       
      
        m-1 
       
      
    m−1个音阶确定后,我们会选择的第 
     
      
       
       
         m 
        
       
      
        m 
       
      
    m个音阶也就确定了,此时选择的音阶就是选择前 
     
      
       
       
         m 
        
       
         − 
        
       
         1 
        
       
      
        m-1 
       
      
    m−1个集合后出现次数为奇数的音阶的集合。
 而我们要选择的前 
     
      
       
       
         m 
        
       
         − 
        
       
         1 
        
       
      
        m-1 
       
      
    m−1个音阶肯定要首先满足前两个条件,总共有 
     
      
       
        
        
          A 
         
         
          
          
            2 
           
          
            n 
           
          
         
           − 
          
         
           1 
          
         
         
         
           m 
          
         
           − 
          
         
           1 
          
         
        
       
      
        A_{2^n-1}^{m-1} 
       
      
    A2n−1m−1个,我们定义满足条件的 
     
      
       
       
         m 
        
       
      
        m 
       
      
    m个音阶的选择方法有 
     
      
       
        
        
          f 
         
        
          i 
         
        
       
      
        f_{i} 
       
      
    fi种。
 我们接下来要使得这个音阶即不为空也未曾出现。
如果它是空集的话,我们去掉最后一个后整个序列仍然是满足条件的,所以我们可以从 
     
      
       
        
        
          A 
         
         
          
          
            2 
           
          
            n 
           
          
         
           − 
          
         
           1 
          
         
         
         
           m 
          
         
           − 
          
         
           1 
          
         
        
       
      
        A_{2^n-1}^{m-1} 
       
      
    A2n−1m−1中减去 
     
      
       
        
        
          f 
         
         
         
           m 
          
         
           − 
          
         
           1 
          
         
        
       
      
        f_{m-1} 
       
      
    fm−1。
 同样,如果有重复出现的,将重复出现的两个数去掉仍然满足条件。
 而重复出现的数有 
     
      
       
       
         m 
        
       
         − 
        
       
         1 
        
       
      
        m-1 
       
      
    m−1个位置, 
     
      
       
        
        
          2 
         
        
          n 
         
        
       
         − 
        
       
         m 
        
       
         + 
        
       
         1 
        
       
      
        2^n-m+1 
       
      
    2n−m+1个位置,要减去 
     
      
       
       
         ( 
        
       
         m 
        
       
         − 
        
       
         1 
        
       
         ) 
        
       
         ( 
        
        
        
          2 
         
        
          n 
         
        
       
         − 
        
       
         m 
        
       
         + 
        
       
         1 
        
       
         ) 
        
        
        
          f 
         
         
         
           m 
          
         
           − 
          
         
           2 
          
         
        
       
      
        (m-1)(2^n-m+1)f_{m-2} 
       
      
    (m−1)(2n−m+1)fm−2。
 所以,我们可以知道
  
      
       
        
        
          A 
         
        
          n 
         
        
          s 
         
        
          = 
         
         
         
           f 
          
         
           m 
          
         
        
          = 
         
         
         
           A 
          
          
           
           
             2 
            
           
             n 
            
           
          
            − 
           
          
            1 
           
          
          
          
            m 
           
          
            − 
           
          
            1 
           
          
         
        
          − 
         
         
         
           f 
          
          
          
            m 
           
          
            − 
           
          
            1 
           
          
         
        
          − 
         
        
          ( 
         
        
          m 
         
        
          − 
         
        
          1 
         
        
          ) 
         
        
          ( 
         
         
         
           2 
          
         
           n 
          
         
        
          − 
         
        
          m 
         
        
          + 
         
        
          1 
         
        
          ) 
         
         
         
           f 
          
          
          
            m 
           
          
            − 
           
          
            2 
           
          
         
        
       
         Ans=f_{m}=A_{2^n-1}^{m-1}-f_{m-1}-(m-1)(2^n-m+1)f_{m-2} 
        
       
     Ans=fm=A2n−1m−1−fm−1−(m−1)(2n−m+1)fm−2
很容易发现,其中的 
     
      
       
       
         f 
        
       
      
        f 
       
      
    f可以通过递推的形式求解。
 时间复杂度 
     
      
       
       
         O 
        
        
        
          ( 
         
        
          n 
         
        
          ) 
         
        
       
      
        O\left(n\right) 
       
      
    O(n)
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int mo=1e8+7;
const int jzm=2333;
const int lim=1000000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-9;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,m,ans,f[MAXN],inv[MAXN],dp[MAXN],pow2[MAXN]; 
int lg(int x){int res=0;while(x)res++,x>>=1;return res-1;}
signed main(){
	read(n);read(m);
	inv[0]=inv[1]=f[1]=dp[0]=pow2[0]=1;pow2[1]=2;
	for(int i=2;i<=1e6;i++)
		f[i]=1ll*(mo-mo/i)*f[mo%i]%mo,
		inv[i]=1ll*inv[i-1]*f[i]%mo,
		pow2[i]=add(pow2[i-1],pow2[i-1],mo);
	if(lg(m)>=n){puts("0");return 0;}int tmp=pow2[n],sum=1;
	for(int i=2;i<=m;i++){
		tmp=add(tmp,mo-1,mo);sum=dp[i]=1ll*sum*tmp%mo;
		dp[i]=add(dp[i],mo-dp[i-1],mo);
		dp[i]=add(dp[i],mo-1ll*dp[i-2]*(i-1)%mo*add(pow2[n],mo-i+1,mo)%mo,mo);
	}
	printf("%d\n",1ll*dp[m]*inv[m]%mo);
	return 0;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号