CF388 D

来源:互联网 发布:美国人如何学编程的 编辑:程序博客网 时间:2024/06/06 02:37

题意:
一个自然数集合S,如果对于所有aSbS都有(a xor b)S,则称S是perfect set。给出n,问有多少个perfect set元素都小于等于n。
n<=10^9

#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<iostream>#define N 35#define mmod 1000000007#define LL long longusing namespace std;int n,a[N],len,f[N][N][2],ans;void upd(int &x,int y){    x=(x+y)%mmod;}void dp(){    f[1][0][1]=f[1][1][0]=1;    for(int i=1;i<len;i++)        for(int j=0;j<=i;j++)            for(int o=0;o<=1;o++)            {                if(f[i][j][o]==0) continue;                if(a[i+1]==1 || o==1)                     upd(f[i+1][j+1][o],f[i][j][o]);                if(o) upd(f[i+1][j][o],(LL)f[i][j][o]*(1ll<<j)%mmod);                else                {                    upd(f[i+1][j][0],(LL)f[i][j][0]*(1ll<<(j-1))%mmod);                    if(a[i+1]) upd(f[i+1][j][1],(LL)f[i][j][0]*(1ll<<(j-1))%mmod);                }            }}int main(){    scanf("%d",&n);    if(n==0) {printf("1\n");return 0;}    int t=n;    while(t) {a[++len]=t%2;t/=2;}    for(int i=1;i<=len/2;i++) swap(a[i],a[len-i+1]);    dp();    for(int i=0;i<=len;i++)        for(int j=0;j<=1;j++)            upd(ans,f[len][i][j]);    printf("%d\n",ans);    return 0;}

题解:
O__O
每个perfect set都可以找出一组基是吧。。
用一种奥妙重重的消元方式能使不同的perfect set消出不同且唯一的基(脑补一下吧)。。
于是我们dp那组线性基。。
用心感受一下吧。。

0 0