CF327E Axis Walking

题意翻译

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

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


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

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

sum很好得到, s u m [ i ] = s u m [ i sum[i]=sum[i sum[i]=sum[i^ l o w b i t ( i ) ] + s u m [ l o w b i t ( i ) ] lowbit(i)]+sum[lowbit(i)] lowbit(i)]+sum[lowbit(i)]

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


AC代码:

#include
#include
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;
}

你可能感兴趣的:(位运算,状压dp)