首页 > 其他分享 >2 つの山札题解

2 つの山札题解

时间:2022-09-22 08:23:37浏览次数:80  
标签:排列 int 题解 序列 1005 山札 转移 mod

题目链接

题意简述:给定两个长度为 \(n\) 的排列 \(A\) 和 \(B\),按照一下方式生成一个长度为 \(2n-2\) 的序列:你对每一个排列分别做 \(n-1\) 次操作,每一次选择一个序列进行操作,删除该排列的第一个数,将另一个排列第一个数加入序列,问最终能得到多少种序列。

数据范围:\(1 \le n \le 10^3\)。

有一个很显然的dp,设 \(f_{i,j}\) 表示保留第一个排列中第 \(i\) 到 \(n\) 个元素和第二个排列中第 \(j\) 到 \(n\) 个元素,进行操作直到两个序列的长度都为 \(1\),能得到的序列数目。

这个dp有一个很naive的转移:\(f_{i,j}=f_{i+1,j}+f_{i,j+1}\),即要么操作序列一,要么操作序列二,倒序枚举计算 \(f\) 数组即可。

但是这样转移会算重,我们来考虑如何去重。

首先,只有 \(A_i=B_j\) 的时候才会算重,而且 \(f_{i.j}\) 多算的部分一定是 \(f_{i+1,j}\) 和 \(f_{i,j+1}\) 中相同的序列数。

设 \(g_{i,j,k}\) 表示 \(f_{i+k,j}\) 与 \(f_{i,j+k}\) 中相同的序列数,状态数 \(n^3\) 级别,显然不行。

但是容易发现,只有当 \(A_i=B_j\) 时,\(g_{i,j,k}\) 才有意义,又由于序列 \(A\) 和 \(B\) 都是排列,一个 \(i\) 唯一对应一个 \(j\),因此 \(i\) 和 \(j\) 中只有一个需要表示进状态,即记 \(g_{i,k}\) 即可。

考虑转移,首先,\(g_{i,k}\) 是 \(f_{i+k,j}\) 和 \(f_{i,j+k}\) 中的重复序列数,其中可能处于此时排列中的第一个位置的数只有可能是 \(a_i\)、\(b_j\)、 \(a_{i+k}\) 和 \(b_{j+k}\),其中可能相等的数对只有 \((a_i,b_j)\) 和 \((a_{i+k},b_{j+k})\)。

因此有两种转移,一种是 \(f_{i+k,j}\) 和 \(f_{i,j+k}\) 分别从 \(f_{i+k+1,j}\) 和 \(f_{i,j+k+1}\) 转移过来,即 \(g_{i,k} \leftarrow g_{i,k+1}\) ,条件是 \(a_i=b_j\) ,根据 \(g\) 的定义,一定满足。

另一种是 \(f_{i+k,j}\) 和 \(f_{i,j+k}\) 分别从 \(f_{i+k,j+1}\) 和 \(f_{i+1,j+k}\) 转移过来,条件是 \(a_{i+k}=b_{j+k}\)。

但是注意,第二种转移不能直接认为是 \(g_{i,k} \leftarrow g_{i+1,k-1}\),因为 \(a_{i+1}\) 和 \(b_{j+1}\) 不一定相等,该转移的正确方式应该为 \(g_{i,k} \leftarrow g_{i+k,1-k}\)。

由于上述转移中用到了 \(g_{i,k}(k \le 0)\),因此 \(k\) 为非正数的 \(g\) 也需要计算,其中 \(g_{i,0}=f_{i,j}\) ,\(k\) 为负数的转移和正数一致,但是要注意,\(g_{i,k}(k <0)\) 的计算不能在倒序枚举到 \(i\) 时计算,而应该在枚举到 \(i+k\) 时计算,因为枚举到 \(i\) 时,\(f_{i-k,j}\) 还没有被计算,因此此时的 \(g_{i,k}\) 还没有意义。

然后 \(f\) 的转移就很简单了,\(f_{i,j}=f_{i+1,j}+f_{i,j+1}-[a_i==b_j]g_{i,1}\),初值为 \(f_{n,n}=1\)。

倒序枚举一下转移 \(f\) 和 \(g\) 即可,注意 \(g_{i,k}(k > 0)\)要在 \(f_{i,j}\) 之前计算,因为 \(f\) 的转移会用到,\(g_{i,0}\) 要在 \(f_{i,j}\) 之后计算,因为它需要从 \(f_{i,j}\) 转移过来。

Code:

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
int n,a[1005],b[1005];
int f[1005][1005];
map<int,int> g[1005];
int id1[1005],id2[1005];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),id1[a[i]]=i;
	for(int i=1;i<=n;i++)
		scanf("%d",&b[i]),id2[b[i]]=i;//记双射,方便查询与 a[i] 相同的 b[j]
	for(int i=n;i>=1;i--)
	{
		int k=id2[a[i]];
		for(int j=n-max(i,k);j>=1;j--)//计算g[i][j](j>0)
		{
			g[i][j]=g[i][j+1];
			if(a[i+j]==b[k+j])
				g[i][j]=(g[i][j]+g[i+j][1-j])%mod;
		}
		for(int j=-1;j>=-n;j--)//计算g[i-j][j](j<0)
		{
			if(i-j>n)
				break;
			int k=id2[a[i-j]];
			g[i-j][j]=g[i-j][j+1];
			if(a[i]==b[k+j])
				g[i-j][j]=(g[i-j][j]+g[i][1-j])%mod;
		}
		for(int j=n;j>=1;j--)//计算f[i][j]
		{
			if(i+j==2*n)
				f[i][j]=1;
			else
			{
				f[i][j]=(f[i+1][j]+f[i][j+1])%mod;
				if(a[i]==b[j])
					f[i][j]=(f[i][j]-g[i][1]+mod)%mod;
		}
		g[i][0]=f[i][k];//计算g[i][0]
	}
	printf("%d\n",f[1][1]);
	
	return 0;
}

标签:排列,int,题解,序列,1005,山札,转移,mod
From: https://www.cnblogs.com/Laoli-2020/p/16717848.html

相关文章

  • 题解 P7839 「Wdoi-3」夜雀 singing (思路非常好的一道题)
    代码细节非常多的一道题。这里只说思想了先。首先,找到那些安全树。所有的乌鸦最后一定会到达某一棵安全树上。因此,对于每只乌鸦,分别向左和向右暴力寻找,看是否可到达安全......
  • FCKEditor粘贴word图片问题解决
    ​ 当前功能基于PHP,其它语言流程大致相同 1.新增上传wordjson配置在ueditor\php\config.json中新增如下配置:     /* 上传word配置 */    "wordAction......
  • IDE//VS//VS2017,VS2019没有代码提示的问题解决
    IDE//VS//VS2017,VS2019没有代码提示的问题解决小小菜鸡于2022-07-2815:24:44发布235 收藏文章标签:idec++visualstudio版权开始菜单-->所有程序–>VisualStudi......
  • 牛客题解 卡牌游戏
    链接:https://ac.nowcoder.com/acm/problem/19777来源:牛客网题解作者岛田小雅在这里先贴一下OIWiki上期望的定义。根据期望的定义和题意,我们可以这样去思考这道高......
  • Mac系统用Maven本地引入jar包报错问题解决
    打包命令mvninstall:install-file-Dfile=/Users/用户名/tool/selenium-server-standalone-3.9.1.jar-DgroupId=org.selenium-DartifactId=selenium-server-standalone......
  • CSP-S模拟6 题解
    开个坑,今后我要写题解了!A.玩水挺有趣的一道题,我们首先从\(2\)条路径的情况考虑符合答案的路径一定满足这种格式:两条路径先重合,再分开,最后再重合观察一下,注意到第一......
  • CF1720E Misha and Paintings 题解
    神仙2700。首先统计出原数组中不同元素个数记作\(cnt\),如果\(cnt\lek\)说明元素个数不够,由于一次只能加一个颜色因此答案就是\(k-cnt\)。然后接下来要证明一个结论......
  • Codeforces Round #821(Div.2) (A-C) 题解
    CodeforcesRound#821(Div.2)(A-C)  A.ConsecutiveSum大致题意给定一组共n个数据,如果俩个数的下标在modk意义下同余,则可以交换a[I]和a[j] ,求操作后一段......
  • Luogu T273083 新的题目 题解
    怕放洛谷有人看,就搬过来了。本题解提供一个\(O(qn)\)的做法(实际上是暴力的优化)。先考虑暴力求解。对于每个操作,要求代价\(W\times(\sum_{i\inX}^{i}w[i]\times......
  • CF1363F题解
    好妙的dp-1的情况就是字母构成的可重集不同我们将一次操作抽象成将一个字符向前移动若干格我们设f[i][j]表示s串到了第i个字母,t串到了第j个字母的最小操作次数1.将第i......