BZOJ 4903: [Ctsc2017]吉夫特 数论+dp

思路很巧妙的一道题 ~          

这个应该不完全是正解,复杂度约为 $O(3\times 10^8)$,有时间再研究研究正解.  

首先,最裸的暴力是按照权值从小到大枚举每一个数,然后枚举后面的数来更新方案数,是 $O(n^2)$ 的.   

然后,我们可以用lucas定理来模拟那个组合数,会发现只需满足大数&小数=小数即可.   

这个的话可以枚举子集,复杂度就是 $O(3^{18})$ 左右的,大概能过 ~ 

code: 

#include <bits/stdc++.h>      
#define ll long long 
#define N 300000   
#define MAX 233333    
#define mod 1000000007   
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int f[N],pos[N];               
int main() 
{    
    // setIO("input");  
    int i,j,n,ans=0;    
    scanf("%d",&n); 
    for(i=1;i<=n;++i) 
    {
        int x; 
        scanf("%d",&x);         
        pos[x]=i;   
    }          
    for(i=1;i<=233333;++i) 
    {           
        if(pos[i])   
        {  
            for(j=i&(i-1);j;j=i&(j-1))     
            {   
                if(pos[j]>pos[i]) 
                {
                    f[i]=(f[i]+f[j]+1)%mod;         
                }
            }
        }
    }   
    for(i=1;i<=233333;++i)  ans=(ans+f[i])%mod;               
    printf("%d\n",ans);   
    return 0; 
}

  

猜你喜欢

转载自www.cnblogs.com/guangheli/p/12055181.html