正题
题目链接:http://noip.ybtoj.com.cn/contest/102/problem/4
题目大意
求有多少个长度为nnn的序列aaa满足1≤ai≤101\leq a_i\leq 101≤ai≤10,且可以找到一组(i,j,k,l)(i,j,k,l)(i,j,k,l)使得(∑p=ij−1ap=x)&(∑p=jk−1ap=y)&(∑p=klap=z)(\sum_{p=i}^{j-1}a_p=x)\&(\sum_{p=j}^{k-1}a_p=y)\&(\sum_{p=k}^{l}a_p=z)(p=i∑j−1ap=x)&(p=j∑k−1ap=y)&(p=k∑lap=z)
解题思路
题意转化为有没有一个(i,j,k,l)(i,j,k,l)(i,j,k,l)使得
(∑p=ijap=x)&(∑p=ikap=x+y)&(∑p=klap=x+y+z)(\sum_{p=i}^{j}a_p=x)\&(\sum_{p=i}^{k}a_p=x+y)\&(\sum_{p=k}^{l}a_p=x+y+z)(p=i∑jap=x)&(p=i∑kap=x+y)&(p=k∑lap=x+y+z)
考虑状压,对于一个iii能被表示在集合中当且仅当满足序列中有一个后缀和iii使得
- x<i<yx<i<yx<i<y且集合中有一个j=xj=xj=x
- y<i<zy<i<zy<i<z且集合中有一个j=yj=yj=y
这样就保证如果集合中有一个zzz那么一定有一个划分xxx和yyy。
预处理gs,ig_{s,i}gs,i表示状态为sss时加入一个iii能够到达的集合
然后设fi,sf_{i,s}fi,s表示加入到第iii个数时到达集合sss的方案数
时间复杂度O(2x+y+z(x+y+z)∗10+n2x+y+z∗10)O(2^{x+y+z}(x+y+z)*10+n2^{x+y+z}*10)O(2x+y+z(x+y+z)∗10+n2x+y+z∗10)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll M=1<<18,XJQ=1e9+7;
ll n,x,y,z,g[M][11],f[45][M];
signed main()
{freopen("poem.in","r",stdin);freopen("poem.out","w",stdout);scanf("%lld%lld%lld%lld",&n,&x,&y,&z);y+=x;z+=y;ll MS=(1<<z);for(ll i=1;i<=MS;i++)for(ll j=1;j<=10;j++){g[i][j]=1;if(i==MS){g[i][j]=MS;continue;}for(ll k=0;k<z;k++){if((i>>k&1)&&k+j<=z&&!(k<x&&k+j>x)&&!(k<y&&k+j>y))g[i][j]|=1<<k+j;if(g[i][j]>MS)g[i][j]=MS;}}f[0][1]=1;for(ll i=0;i<n;i++)for(ll j=1;j<=MS;j++){if(!f[i][j])continue;for(ll k=1;k<=10;k++)(f[i+1][g[j][k]]+=f[i][j])%=XJQ;}printf("%lld",f[n][MS]);
}