CF327E Axis Walking

不问归期 提交于 2020-02-22 22:45:44

题意翻译

给你一个长度为n(1<=n<=24)的正整数序列S,再有k(0<=k<=2)个正整数。

求有多少种S的排列方式使得其前缀和不会成为那k个数里的任意一个。 答案对1e9+7取模。


题解:
n<=24,考虑状压DP

设dp[S]表示当前已选的集合为S,sum[S]为当前集合的数的和

sum很好得到,sum[i]=sum[isum[i]=sum[i^lowbit(i)]+sum[lowbit(i)]lowbit(i)]+sum[lowbit(i)]

dp[S]可以由dp[x](xS)\sum dp[x](x∈S)得到,而x可以通过枚举S中的1,然后异或即可得到


AC代码:

#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define LL long long
#define endl '\n'
const int MAXN = 1<<24;
const int MAXM = 1e6+50;
const int MOD = 1e9+7;
const double PI = acos(-1);
inline char getc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    int x=0,f=1; char ch=getc();
    while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getc(); }
    while(isdigit(ch)) x=x*10+ch-48,ch=getc();
    return x*f;
}
int sum[MAXN],dp[MAXN],a[30],lim[5],n,k;
inline int lowbit(int x){ return x&-x; }
signed main(){
#ifndef ONLINE_JUDGE
    freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
    n=read();
    for(int i=0;i<n;i++) a[i]=read(),sum[1<<i]=a[i];
    k=read();
    for(int i=0;i<k;i++) lim[i]=read();
    for(int i=0;i<n;i++)
        if(a[i]!=lim[0] && a[i]!=lim[1])
            dp[1<<i]=1;
    for(int i=1;i<(1<<n);i++){
        sum[i]=sum[i^lowbit(i)]+sum[lowbit(i)];
        if(sum[i]==lim[0] || sum[i]==lim[1]) continue;
        for(int j=i;j;j-=lowbit(j))
            dp[i]=(dp[i]+dp[i^lowbit(j)])%MOD;
    }
    cout<<dp[(1<<n)-1]<<endl;
    return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!