首页 > 其他分享 >题解:[TJOI2018] 游园会

题解:[TJOI2018] 游园会

时间:2024-08-20 09:15:41浏览次数:8  
标签:ch LCS int 题解 long 游园会 TJOI2018 dp define

所谓 dp套dp ,实际上就是在说求解一个 dp 的过程中,我们用另一个 dp 求解出他应该从某个状态转移到另一个状态。

考虑一下这道题,首先求 LCS 的 dp 如下:

\[dp_{i,j}=\max\{dp_{i-1,j},dp_{i,j-1},dp_{i-1,j-1}+[s_i==t_j]\} \]

显然,当\(i\)固定的时候,\(dp_{i,j}\)是单调不降的,且相邻两个数的差\(\in[0,1]\),考虑直接状压这个东西,其实相当于就是在说当\(i\)一定的时候,这个\(dp\)识字长什么样。

考虑设\(f_{i,S,0/1/2}\)表示当考虑了兑奖串的前\(i\)位的时候,LCS 的\(dp\)式子状压下来为\(S\),最后几位同NOI的匹配到了第几位,此时的方案数。

设\(sta_{S,j}\)表示 LCS 的\(dp\)式子状压下来为\(S\)后新加入一位\(j\)后的\(dp\)式子状压下来的情况,具体求解类似LCS 的内层 \(dp\)。

状态转移:

\[f_{i,sta_{S,x},nxt_{y,x}}\to f_{i,sta_{S,x},nxt_{y,x}}+f_{i-1,S,y} \]

\(nxt_{x,y}\)表示下一个NOI匹配的状态,初始状态设\(f_{0,0,0}=1\)。

时间为\(\mathcal{O}(n2^k+k2^k)\),注意状态压缩。

#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define p_b push_back
#define m_p make_pair
#define pii pair<int,int>
#define val first
#define id second
#define ls k<<1
#define rs k<<1|1
#define mid ((l+r)>>1)
#define gcd __gcd
#define lowbit(x) (x&(-x))
#define popcount __builtin_popcount
using namespace std;
int rd(){
    int x=0,f=1; char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if (ch=='-') f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return x*f;
}
void write(int x){
    if(x>9) write(x/10);
    putchar('0'+x%10);
}
const int N=1000+5,M=15,INF=0x3f3f3f3f3f3f3f3f,mod=1e9+7;

int sta[(1<<M)+5][3],f[2][(1<<M)+5][3],dp[2][M<<1],nxt[3][3]={{1,0,0},{1,2,0},{1,0,3}};
int n,m,b[M<<1],state,ans[N];
void init(){
	for(int s=0;s<=state;s++){
		for(int i=0;i<m;i++) dp[0][i+1]=dp[0][i]+((s>>i)&1);
		for(int j=0;j<=2;j++){
			for(int i=1;i<=m;i++){
				dp[1][i]=max(dp[1][i-1],dp[0][i]);
				if(b[i]==j) dp[1][i]=max(dp[1][i],dp[0][i-1]+1);
			}
			int S=0;
			for(int i=1;i<=m;i++) if(dp[1][i]>dp[1][i-1]) S|=(1<<(i-1));
			sta[s][j]=S;
		}
	}
}

void add(int &x,int y){
	x+=y;
	if(x>mod)x-=mod;
}
signed main(){
	n=rd(),m=rd();
	for(int i=1;i<=m;i++){
		char ch=getchar();while(ch<'A'||ch>'Z') ch=getchar();
		if(ch=='N') b[i]=0;
		else if(ch=='O') b[i]=1;
		else b[i]=2;
	}
	state=(1<<m)-1;
	init();
	int now=1;
	f[0][0][0]=1;
	for(int i=1;i<=n;i++){
		memset(f[now],0,sizeof(f[now]));
		for(int s=0;s<=state;s++){//上一个的状压
			for(int x=0;x<=2;x++){//现在第i个加入啥
				for(int y=0;y<=2;y++){//之前匹配到了第几位
					int tmp=nxt[y][x];
					if(tmp==3) continue;
					add(f[now][sta[s][x]][tmp],f[now^1][s][y]);
				}
			}
		}
		now^=1;
	}
	now^=1;
	for(int s=0;s<=state;s++){
		for(int i=0;i<=2;i++){
			add(ans[popcount(s)],f[now][s][i]);		
		}
	}
	for(int i=0;i<=m;i++)printf("%lld\n",ans[i]);
    return 0;
}

标签:ch,LCS,int,题解,long,游园会,TJOI2018,dp,define
From: https://www.cnblogs.com/123456xwd/p/18368731

相关文章

  • 【LGR-196-Div.4】洛谷入门赛 #26 题A - H 详细题解--优化思路简洁代码(C++,Python语
    前言:    觉得这个比赛很有意思的,都是暴力题,涉及一些细节,难度比较适合刚学编程语言的,可以很好的锻炼基础还有手速,最后两题也是比较有意思,之后也准备更新atc的比赛题解和洛谷的一些高质量比赛题解(算法网瘾就是想参加各种比赛)   如果觉得有帮助,或者觉得我写的好,......
  • [NOI]2024 登山 题解
    好像在洛谷题解区里还没人和我做法一样,,?考场做法,只用到了倍增和线段树,感觉挺好写。考场上从开题到过题只用了2h。最底下有省流版(?)。以下是我考场里比较详细的思路,所以比较长。先考虑如何\(O(n^2)\)做,然后再想优化。容易先想到一个状态数是\(O(n^2)\)的DP,即记录起点,并将向......
  • AGC002 题解
    目录A-RangeProductB-BoxandBallC-KnotPuzzleA-RangeProduct分情况讨论:\(a\le0\leb\)时,乘积一定为\(0\);否则:\(0<a\leb\)时,乘积一定为正;否则,负数的个数有\(b-a+1\)个,判断这个数是否为奇数,若是,乘积为负,否则为正。#include<bits/stdc++.h......
  • P10423题解
    P10423[蓝桥杯2024省B]填空问题先贴上答案#include<iostream>usingnamespacestd;intmain(){stringans[]={"1204","1100325199.77",};charT;cin>>T;cout<<ans[T-'A']......
  • P10155题解
    1题意给定一个排列ppp,每次可以选择一个数pi......
  • AT_abc027_b题解
    说明需要掌握贪心算法。这么简单为什么是黄题啊?题意给定一个长度为的非负整数序列,你可以进行若干次操作,每次操作都可以选择一个长度为的子串,花费的代价,将其中的每个数都变成该子串的平均值,现在你必须将每个数都变成相同的,你必须同时保证每个数为非负整数。分析先算......
  • 题解:「ROI 2017 Day 2」存储器
    题目信息题目链接LuoguP10653、LOJ2770题目描述给定一个字符串\(S\),设其长度为\(n\),每个字符要么是+要么是-。定义一个片段为\(S\)的一个子串\(S[l,r]\)满足下面三个条件:\(l=1\)或者\(S_{l-1}\neS_l\)。\(r=n\)或者\(S_{r+1}\neS_r\)。\(S_l=S_{l+1}=......
  • P6218 [USACO06NOV] Round Numbers S 题解
    题面题目传送门如果一个正整数的二进制表示中,00的数目不小于11的数目,那么它就被称为「圆数」。例如,99的二进制表示为10011001,其中有22个00与22个11。因此,99是一个「圆数」。请你计算,区间[l,r][l,r]中有多少个「圆数」。前置芝士1.数位dp相关的题:P4317花神......
  • [题解]UVA1127 Word Puzzles
    UVA1127WordPuzzles我们对模式串建立AC自动机,然后就比较板子了,只需要把\(8\)个方向都跑一遍匹配就可以了。时间复杂度是\(O(T\times8nm)\)。注意输入是大写字母。点击查看代码#include<bits/stdc++.h>#defineK1010//模式串个数&矩阵长宽#defineN1000010//节点个......
  • el-table使用sortablejs推拽排序卡顿问题解决
    使用sortablejs拖拽el-table排序时,对于纯文本表格,正常使用即可,不会卡顿initSort(){consttbody=document.querySelector('.el-table__body-wrappertbody')const_this=thisSortable.create(tbody,{draggable:'.el-table__row',......