Flowey 是一朵能够通过友谊颗粒传播LOVE 的小花.它的友谊颗粒分为两种,
圆粒的和皱粒的,它们依次排列组成了一个长度为2m 的序列.对于一个友谊颗
粒的序列,如果存在1<=i< j <=2m,满足以下条件:
1 i 为偶数,j 为奇数
2 第i 颗友谊颗粒和第j 颗友谊颗粒同为圆粒或同为皱粒
3 第i 颗友谊颗粒和第j 颗友谊颗粒都还没有被使用过
那么,就可以使用这两颗友谊颗粒,然后提升一次LV.
定义一个友谊颗粒的序列为高效的,当且仅当尽可能多的提升LV 后,序列
上剩余的友谊颗粒数量不超过2n。
现在,Flowey 想知道,长度为2m 的友谊颗粒序列,有多少个不同的序列是
高效的?
定义两个友谊颗粒序列是不同的,当且仅当存在1<=i<=2m,第i 颗友谊颗粒在
一个序列中为圆粒,而在另一个中为皱粒.
由于答案可能很大,你只需要求出答案对p 取模的结果.
对于60%的数据,满足n<=300,m<=300
对于100%的数据,满足1<=n<=3000,1<=m<=3000,p<=1e9+7
将奇偶分开,偶一排放上面,奇一排放下面,球有颜色,上下同色匹配(匹配形如“”或“|”),要求匹配数>=n,求给球赋值颜色的方案数
dp显然
f[i][j][k]表示下面到第i个,上面剩余失配白色数为j,失配黑色数为k
枚举当前第i列上下颜色转移
状态O(n^3)转移O(1)
不dp很难做,着手于优化dp状态
可以发现,有一个约束条件j+k<=n,考虑能否把k那一维省掉
设g[i][j],i,j 含义同上,那么k<=n-j, g[i][j]=∑n−jk=0f[i][j][k]
但是这样会算重,如果对于一组序列它最后为匹配的白色数为a,黑色为b
有a<=j && b<=n-j 且 a<=j’ && b<=n-j’
那么这一组序列在g[i][j]与g[i][j’]都会被计算
我们考虑当且仅当a=j 的时候计算,而对于a< j 且也合法的状态就不算了。这样只会被算一次
什么时候a=j呢,那么就应该是中间某个时刻出现了j=0(感受一下)
反证很显然:如果a>j,那么始终有j>0
于是多一维状态表示是否曾经出现了j=0,如果是才计入答案
状态O(n^2)转移O(1)
#include<ctime>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
#define efo(i,v,u) for(int i=last[v],u=to[i];i;i=next[i],u=to[i])
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define mset(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
typedef double db;
char ch;
void read(int &n)
{n=0;int p=1;for(ch=getchar();ch<'0' || ch>'9';ch=getchar())if(ch=='-') p=-1;for(;'0'<=ch && ch<='9';ch=getchar()) n=n*10+ch-'0';n*=p;
}
const int N=3005;
int n,m,mo,f[N][N][2];
void update(int &x,ll y){x=(ll)(x+y)%mo;}
int main()
{freopen("friend.in","r",stdin);//freopen("friend.out","w",stdout);read(n),read(m),read(mo);--n,--m;fo(i,0,n) f[0][i][(i==0)]=1;fo(i,0,m){update(f[i+1][0][1],2*f[i][0][1]);//0 0;1 1;update(f[i+1][1][1],f[i][0][1]);//0 1fo(j,1,n){update(f[i+1][j][0],2*f[i][j][0]);update(f[i+1][j][1],2*f[i][j][1]);//0 0;1 1;if(j<n){update(f[i+1][j+1][0],f[i][j][0]);update(f[i+1][j+1][1],f[i][j][1]);}//0 1if(j>1){update(f[i+1][j-1][0],f[i][j][0]);update(f[i+1][j-1][1],f[i][j][1]);}else update(f[i+1][j-1][1],f[i][j][0]+f[i][j][1]);//1 0}}int ans=0;fo(i,0,n) update(ans,f[m][i][1]);printf("%d",(ll)ans*4%mo);return 0;
}
本文发布于:2024-01-30 13:41:23,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170659328620394.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |