USACO 2020 December Platinum

A. Sleeping Cows

首先一个简单的想法是枚举最小的为匹配的 \(s\),则限定了 \(s\) 的一段前缀匹配和 \(t\) 的一段后缀匹配其他随意。

这样我们就几乎得到了一个 \(O(n^3)\) 的做法,即 \(O(n)\) 枚举位置,\(O(n^2)\) dp

考虑对于确定的 \(s\)\(t\) 如何计算其完美匹配个数,显然是排序之后的一个累乘,但我们发现不好利用这个式子设计状态。

其实只用最经典的括号匹配式 dp 就能轻松解决了,就是把 \(s\)\(t\) 放进一个数组里排序出来然后分别记录位置和未匹配个数。

考虑如何优化。我们要使得每一个未匹配的 \(t\) 都不存在在前面的 \(s\) 未匹配,你发现这十分容易处理,记一位 \(0/1\) 表示当前是否所有 \(s\) 都要求匹配即可。

那么显然有转移方程:

如果当前是 \(s\)

\[dp_{i,j,0}=dp_{i-1,j,0}+dp_{i-1,j,1}+dp_{i-1,j-1,0}\\dp_{i,j,1}=dp_{i-1,j-1,1} \]

如果当前是 \(t\)

\[dp_{i,j,0}=(j+1)dp_{i-1,j+1,0}\\dp_{i,j,1}=dp_{i-1,j,1}+(j+1)dp_{i-1,j+1,1} \]

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=3e3+5; 
int n,m,dp[N<<1][N][2];
#define pii pair<int,int>
#define fi first
#define se second
#define mkp make_pair
pii a[N<<1];
int main(){
	n=read();dp[0][0][1]=1;
	for(int i=1,x;i<=n;i++)
		x=read(),a[i]=mkp(x,0);
	for(int i=1,x;i<=n;i++)
		x=read(),a[n+i]=mkp(x,1);
	sort(a+1,a+1+n+n);
	for(int i=1;i<=n+n;i++)
		for(int j=0;j<=n;j++){
			if(a[i].se){
				dp[i][j][0]=1ll*(j+1)*dp[i-1][j+1][0]%mod;
				dp[i][j][1]=(dp[i-1][j][1]+1ll*(j+1)*dp[i-1][j+1][1])%mod;
			}else{
				dp[i][j][0]=(0ll+dp[i-1][j][0]+dp[i-1][j][1]+(j?dp[i-1][j-1][0]:0))%mod;
				dp[i][j][1]=(j?dp[i-1][j-1][1]:0);
			}
		}
	printf("%d\n",(dp[n+n][0][0]+dp[n+n][0][1])%mod);
	return 0;
}

Spaceship

标签害人好吧,要是不看到矩阵的标签我应该能想到个大概。

其实类似于 THUPC 的一道题,还是一个高维 dp,先考虑不管头尾怎么做。

\(dp_{h,i,j}\) 为最大为 \(h\),从 \(i\)\(j\),我发现很多图上问题都难以确定转移顺序,但是但凡多带了一维层数就非常好转移。

\[dp_{h,i,j}\leftarrow dp_{h-1,i,j}\\dp_{h,i,j}\leftarrow \sum_k \sum_{(u,k),(k,v)\in E} dp_{h-1,i,u}dp_{h-1,v,j} \]

其中 \(u,v\) 显然可以预处理掉,至于首位的话新开一个点就好了,时间复杂度 \(O(nm(n+q)^2)\)

#include<bits/stdc++.h>
using namespace std;
#define inf 1e9
const int maxn=2e5+10;
const int mod=1e9+7;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return x*f;
}
const int N=61;
int n,m,q,f[N][N+N][N+N],G[N][N];
int bs[N],s[N],bt[N],t[N],l[N+N],r[N+N];
inline void add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
int main(){
	n=read(),m=read(),q=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			scanf("%1d",&G[i][j]);
	for(int i=1;i<=q;i++)
		bs[i]=read(),s[i]=read(),bt[i]=read(),t[i]=read();
	for(int h=1;h<=m;h++){
		for(int i=1;i<=n+q;i++)
			for(int j=1;j<=n+q;j++)
				f[h][i][j]=f[h-1][i][j];
		for(int k=1;k<=n;k++){
			for(int i=1;i<=n+q;i++)l[i]=r[i]=0;
			l[k]=r[k]=1;
			for(int i=1;i<=q;i++){
				l[i+n]=(bs[i]==h&&s[i]==k);
				r[i+n]=(bt[i]==h&&t[i]==k);
			}
			for(int i=1;i<=n+q;i++)
				for(int j=1;j<=n;j++){
					if(G[j][k])add(l[i],f[h-1][i][j]);
					if(G[k][j])add(r[i],f[h-1][j][i]);
				}
			for(int i=1;i<=n+q;i++)
				for(int j=1;j<=n+q;j++)
					f[h][i][j]=(f[h][i][j]+1ll*l[i]*r[j])%mod;
		}
	}
	for(int i=1;i<=q;i++)
		printf("%d\n",f[m][n+i][n+i]);
	return 0;
}
posted @ 2022-04-03 11:09  syzf2222  阅读(32)  评论(0编辑  收藏  举报