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;
}