想了一会儿证了一下性质就出来了
乍一看,背包板子(但数据范围不对
仔细一看,v<=3从这方面下手,物品按体积分为三类,枚举一类,三分一类,另一类应变,最后O(nlogn)
性质:选点顺序与最后的答案无关
所以我们可以枚举该点选不选,然后O(n)维护当前的连边(用二进制表示),然后就行了
(我考场上为什么只维护了一个点的连边啊啊啊)
想想就生气啊啊啊。
题面模数写错了,我应该是60的啊。
然后dp加个前缀和优化就A了,555。
本题最烦的是环,所以我们将枚举答案的各种情况直接改为枚举最后一个男生女生交接的地方,例如:
11001100110101 -> 11100110011010
我们先解决一个子问题:假设它不是一个环,但开始的一段和结尾的一段不能是同种人
这很容易解决,设dp[i][j][k][l]表示已经枚举了i个男的j个女的第一段的性别为k当前这一段的性别为l。
for(int i=1;i<=a;++i) dp[i][0][0][0]=1; for(int i=1;i<=b;++i) dp[0][i][1][1]=1; //预处理 for(int k=1;k<=a&&k<=i;++k){ dp[i][j][0][0]+=dp[i-k][j][0][1]; dp[i][j][1][0]+=dp[i-k][j][1][1]; dp[i][j][0][0]%=mod;dp[i][j][1][0]%=mod; } for(int k=1;k<=b&&k<=j;++k){ dp[i][j][0][1]+=dp[i][j-k][0][0]; dp[i][j][1][1]+=dp[i][j-k][1][0]; dp[i][j][0][1]%=mod;dp[i][j][1][1]%=mod; }
11001100110101(序列A) <-> 11100110011010(序列B)& 2(序列B的位置2开始的为序列A)
而序列B的求法我们已经知道了,对于每1个可能的序列B,它能增加k种序列A的可能(k为第一个连续段的长度)
第一个连续段的长度?
所以我们只需要把
for(int i=1;i<=a;++i) dp[i][0][0][0]=1; for(int i=1;i<=b;++i) dp[0][i][1][1]=1;
for(int i=1;i<=a;++i) dp[i][0][0][0]=i; for(int i=1;i<=b;++i) dp[0][i][1][1]=i;
就行了
然后我们将dp式子前缀和优化一下就过了
#include<bits/stdc++.h> #define M 1005 #define mod 1000000000 using namespace std; int n,m,a,b; long long dp[M][M][2][2],qian[M][M][2][2]; //已经枚举了i个男的,j个女的,第一段为k,当前这一段为l int main(){ // freopen("treat.in","r",stdin); // freopen("treat.out","w",stdout); scanf("%d%d%d%d",&n,&m,&a,&b);a=min(a,n);b=min(b,m); for(int i=1;i<=a;++i) qian[i][0][0][0]=dp[i][0][0][0]=i; for(int i=1;i<=b;++i) qian[0][i][1][1]=dp[0][i][1][1]=i; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ // for(int k=1;k<=a&&k<=i;++k){ // dp[i][j][0][0]+=dp[i-k][j][0][1]; // dp[i][j][1][0]+=dp[i-k][j][1][1]; // dp[i][j][0][0]%=mod;dp[i][j][1][0]%=mod; // } // for(int k=1;k<=b&&k<=j;++k){ // dp[i][j][0][1]+=dp[i][j-k][0][0]; // dp[i][j][1][1]+=dp[i][j-k][1][0]; // dp[i][j][0][1]%=mod;dp[i][j][1][1]%=mod; // } dp[i][j][0][0]=qian[i-1][j][0][1]-(i>a?qian[i-a-1][j][0][1]:0); dp[i][j][1][0]=qian[i-1][j][1][1]-(i>a?qian[i-a-1][j][1][1]:0); dp[i][j][0][1]=qian[i][j-1][0][0]-(j>b?qian[i][j-b-1][0][0]:0); dp[i][j][1][1]=qian[i][j-1][1][0]-(j>b?qian[i][j-b-1][1][0]:0); for(int k=0;k<2;++k) for(int l=0;l<2;++l) dp[i][j][k][l]%=mod,dp[i][j][k][l]+=mod,dp[i][j][k][l]%=mod; qian[i][j][0][0]=(qian[i][j-1][0][0]+dp[i][j][0][0])%mod; qian[i][j][1][0]=(qian[i][j-1][1][0]+dp[i][j][1][0])%mod; qian[i][j][0][1]=(qian[i-1][j][0][1]+dp[i][j][0][1])%mod; qian[i][j][1][1]=(qian[i-1][j][1][1]+dp[i][j][1][1])%mod; // printf("%d %d %lld %lld %lld %lld\n",i,j,dp[i][j][0][0],dp[i][j][1][0],dp[i][j][0][1],dp[i][j][1][1]); } dp[n][m][0][1]+=dp[n][m][1][0]; dp[n][m][0][1]%=mod; printf("%lld",dp[n][m][0][1]); return 0; }
std的做法回头再研究一下吧