2024/7/23 测试小结
突然听说要考试捏(
没有复习(
T1 是 P1434 [SHOI2002] 滑雪。
草这不一眼......等下好像不太会写。一开始脑抽了。暴力建图给每个点跑spfa最长路。
明显地,不是正解。直接跳掉了。
T2 是 P4170 [CQOI2007] 涂色。
草这真的是一眼题。10min秒掉。区间dp板子。
设 \(dp_{i,j}\) 表示区间 \([i,j]\) 的答案。状态转移如下。
\(dp_{i,j}=\begin{cases}\min\{dp_{i,j-1},dp_{i+1,j}\}&(s_i = s_j)\\\min\limits_{k=i}^{j-1} \{dp_{i,k}+dp_{k+1,j}\}&\text{else}\end{cases}\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,dp[505][505];
string str;
signed main(){
freopen("kokoa.in","r",stdin);
freopen("kokoa.out","w",stdout);
cin>>str;
n=str.size();
str=" "+str;
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++) dp[i][i]=1;
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
if(str[i]==str[j]) dp[i][j]=min(dp[i+1][j],dp[i][j-1]);
else{
for(int k=i;k<j;k++){
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);
}
}
}
}
cout<<dp[1][n]<<endl;
return 0;
}
T3 是 CF161D Distance in Tree。一眼淀粉质,可惜不会写。
首先想到计数dp。推了个扇贝式子。于是放弃。过了5min,发现这不一眼简单树形dp吗?
设 \(dp_{i,j}\) 表示以 \(i\) 为根的子树内从 \(i\) 开始长度为 \(j\) 的路径数量。
设当前节点为 \(x\),一个邻接点为 \(y\),贡献即为 \(\sum\limits_{i=0}^{k-1} dp_{y,i} dp_{x,k-i-1}\)。
对于一个 \(1 \le j \le k\),每次转移将 \(dp_{x,j}\) 加上 \(dp_{y,j-1}\) 即可。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k;
struct node{
int to,nxt;
}w[114514];
int h[114514],cnt=0;
void Link(int x,int y){
++cnt;
w[cnt].to=y;
w[cnt].nxt=h[x];
h[x]=cnt;
return ;
}
int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
return x*f;
}
int ans=0,dp[114514][505];
void dfs(int x,int fa){
dp[x][0]=1;
for(int i=h[x];i!=0;i=w[i].nxt){
int y=w[i].to;
if(y==fa) continue;
dfs(y,x);
for(int j=0;j<k;j++) ans+=dp[y][j]*dp[x][k-j-1];
for(int j=1;j<=k;j++) dp[x][j]+=dp[y][j-1];
}
return ;
}
signed main(){
freopen("rize.in","r",stdin);
freopen("rize.out","w",stdout);
n=read(); k=read();
for(int i=1;i<n;i++){
int u,v;
u=read(); v=read();
Link(u,v);
Link(v,u);
}
dfs(1,0);
cout<<ans<<endl;
return 0;
}
T4 是 CF1073E Segment Sum。一眼数位dp。但又不会写。于是骗分。
T5 是 LibreOJ #6039「NAIPC2016」Jewel Thief,骗分。
最后看回T1。真的傻了。直接敲个记搜。应该能过。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,a[2005][2005];
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
return x*f;
}
int dp[2005][2005];
int qwq(int x,int y){
if(dp[x][y]) return dp[x][y];
int qans=0;
if(x+1<=n&&a[x+1][y]<a[x][y]) qans=max(qans,qwq(x+1,y));
if(x-1>=1&&a[x-1][y]<a[x][y]) qans=max(qans,qwq(x-1,y));
if(y+1<=m&&a[x][y+1]<a[x][y]) qans=max(qans,qwq(x,y+1));
if(y-1>=1&&a[x][y-1]<a[x][y]) qans=max(qans,qwq(x,y-1));
return dp[x][y]=qans+1;
}
signed main(){
freopen("chino.in","r",stdin);
freopen("chino.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
}
}
int qaq=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(dp[i][j]) qaq=max(qaq,dp[i][j]);
else qaq=max(qaq,qwq(i,j));
}
}
cout<<qaq<<endl;
return 0;
}
预计得分:[70,100]+100+100+20+10=[300,330]
实际得分:100+100+100+20+0=320
暴力打错了。于是 班rk5 总rk19/59。