ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[LNOI2022] 题

2022-06-01 19:32:28  阅读:162  来源: 互联网

标签:LNOI2022 方案 状态 int 组内 个数 dp


题意:

建议看原题面,抽象文字会严谨很多。
给长为\(3*n\)的字符串s,每个位置值为\([0,3]\),如果为\(0\)的话,你构造字符串\(t\),即把\(0\)替换为\([1,3]\)。如果\(t\)中每三个配对(前提是为排列,且按编号从前往后的逆序对奇数),问配出的\(n\)对的方案数,方案不同当且仅当\(t\)不同或者任意两对三个值对应下标有一个不同。

思路:

感觉自己没有创造力,\(n<=19\)以为是状压,结果是\(o(n^7)\)摩天轮大dp。
逆序对奇数,即\(132,213,321\)三种情况。
我一开始是把问题拆看看的,先构造\(t\),再看对应方案数。其实发现这种\(?\)填充问题+dp的话,都会直接在决策转移\(?\)时考虑选择,且存在同一个状态里。
该题正确的解读方式:分组(匹配)的方案数。
发现一组大小\(3\)其实很小,如果再小一点,是\(2\)呢?
一组大小为\(2\),组中第一个加入时,加入状态。
如果大小为\(3\),同理存第一个元素状态,(可更新前两个元素状态)因此存前两个状态,因此也可以转移第三个填入。
这道题的状态就出来了:
\(dp[i][x][y][z][o][p][q]\):表到\(t\)前\(i\)位,组内只有\(1\)个数\(x\),\(2\)个数为\(y\),\(3\)个数为\(z\),组内只有\(32\)个数为\(o\),组内只有\(13\)个数为\(p\),组内只有\(21\)个数为\(q\)。
结果为\(dp[3n][0][0][0][0][0][0]*n!\)
因为每一种\(n\)个组方案的其实是按最后一个元素的下标有序的。所以\(n\)个组,可打乱顺序,要乘\(n!\)。
转移就:组内已填大小:\(0-1/1->2/2->3\)
注意乘系数(可加入组的方案数),还有第一维\(3*n\)会暴要滚掉!
具体方程可见code.

code:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=20;
int n,dp[2][N][N][N][N][N][N];
char ch[N*3];
void DP(bool cur,bool lst,int opt) {
	if(opt==1) {
		for(int x=0;x<=n;x++) for(int y=0,up=n-x;y<=up;y++) for(int z=0,up=n-x-y;z<=up;z++) {
			for(int o=0,up=n-x-y-z;o<=up;o++) for(int p=0,up=n-x-y-z-o;p<=up;p++) for(int q=0,up=n-x-y-z-o-p;q<=up;q++) {
				if(x)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+dp[lst][x-1][y][z][o][p][q])%mod;
				if(y<n&&q)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+1ll*dp[lst][x][y+1][z][o][p][q-1]*(y+1))%mod;
				if(o<n)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+1ll*dp[lst][x][y][z][o+1][p][q]*(o+1))%mod;
			}
		}
	}
	else if(opt==2) {
		for(int x=0;x<=n;x++) for(int y=0,up=n-x;y<=up;y++) for(int z=0,up=n-x-y;z<=up;z++) {
			for(int o=0,up=n-x-y-z;o<=up;o++) for(int p=0,up=n-x-y-z-o;p<=up;p++) for(int q=0,up=n-x-y-z-o-p;q<=up;q++) {
				if(y)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+dp[lst][x][y-1][z][o][p][q])%mod;
				if(z<n&&o)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+1ll*dp[lst][x][y][z+1][o-1][p][q]*(z+1))%mod;
				if(p<n)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+1ll*dp[lst][x][y][z][o][p+1][q]*(p+1))%mod;
			}
		}
	}
	else {
		for(int x=0;x<=n;x++) for(int y=0,up=n-x;y<=up;y++) for(int z=0,up=n-x-y;z<=up;z++) {
			for(int o=0,up=n-x-y-z;o<=up;o++) for(int p=0,up=n-x-y-z-o;p<=up;p++) for(int q=0,up=n-x-y-z-o-p;q<=up;q++) {
				if(z)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+dp[lst][x][y][z-1][o][p][q])%mod;
				if(x<n&&p)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+1ll*dp[lst][x+1][y][z][o][p-1][q]*(x+1))%mod;
				if(q<n)dp[cur][x][y][z][o][p][q]=(dp[cur][x][y][z][o][p][q]+1ll*dp[lst][x][y][z][o][p][q+1]*(q+1))%mod;
			}
		}
	}
}
void Clear(int opt) {
	for(int x=0;x<=n;x++) for(int y=0,up=n-x;y<=up;y++) for(int z=0,up=n-x-y;z<=up;z++) {
		for(int o=0,up=n-x-y-z;o<=up;o++) for(int p=0,up=n-x-y-z-o;p<=up;p++) for(int q=0,up=n-x-y-z-o-p;q<=up;q++) {
			dp[opt][x][y][z][o][p][q]=0;
		}
	}
}
int main() {
	int T;scanf("%d",&T);
	while(T--) {
		scanf("%d",&n);
		scanf("%s",ch);
		dp[0][0][0][0][0][0][0]=1;
		ll ans=1;
		for(int i=1;i<=3*n;i++) {
			bool cur=i&1,lst=cur^1;
//			printf("i=%d(cur=%d)::~~~\n",i,cur);
			if(ch[i-1]=='1') {DP(cur,lst,1);}
			else if(ch[i-1]=='2') {DP(cur,lst,2);}
			else if(ch[i-1]=='3') {DP(cur,lst,3);}
			else {
				DP(cur,lst,1),DP(cur,lst,2),DP(cur,lst,3);
			}
			Clear(lst);
		}
		for(int i=1;i<=n;i++)ans=ans*i%mod;
		printf("%lld\n",ans*dp[(n*3)&1][0][0][0][0][0][0]%mod);
		Clear(n&1); 
	} 
	return 0;
}

标签:LNOI2022,方案,状态,int,组内,个数,dp
来源: https://www.cnblogs.com/bestime/p/16335382.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有