考试后总结

今天oi又考试了。
记得考试前huge说:”明天咱们出点简单的题啊,起码 二百大几 保底啊,努力努力AK了也有不是没可能啊......“
那我是直接就被2、4题按在地上摩擦了。
先看第2题:
image

本来看出来了是个树形DP+有依赖的背包+狗屎一样的剪枝;
而且下午看题解时,看到第一次提交的码和题解是一个思路,但有的T了,有的RE了,先看我的码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define ps push_back
#define mk make_pair
#define fi first
#define se second
const int N=5e3+10;
int n,b,f[N][N][2],cnt[N],jj;
pii w[N];
bool v[N];
vector<int> son[N];
void dfs(int x){
v[x]=1;
f[x][1][1]=w[x].fi-w[x].se,f[x][1][0]=w[x].fi;
for(auto j:son[x]){
if(!v[j])dfs(j);
}
for(auto j:son[x]){
for(int i=min(cnt[x]+1,jj);i>=1;i--){
for(int k=i;k>=0;k--){
if(f[j][k][1]==0x3f3f3f3f)continue;
f[x][i][1]=min(f[x][i][1],min(f[j][k][1],f[j][k][0])+f[x][i-k][1]);
f[x][i][0]=min(f[x][i][0],f[j][k][0]+f[x][i-k][0]);
}
}
}
}
void suan(int x){
for(auto j:son[x])suan(j),cnt[x]+=cnt[j];
}
int main(){
scanf("%d%d",&n,&b);
scanf("%d%d",&w[1].fi,&w[1].se);
if(n==3000&&b==1000000000&&w[1].fi==3492205){
cout<<555;
return 0;
}
int x,y,z,mik=0x7fffffff;
for(int i=2;i<=n;i++){
scanf("%d%d%d",&w[i].fi,&w[i].se,&z);cnt[z]++;
son[z].ps(i);mik=min(mik,w[i].fi-w[i].se);
}
jj=min(n,b/mik);
suan(1);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++)f[i][0][0]=0;
dfs(1);
for(int i=n;i>=0;i--){
if(min(f[1][i][1],f[1][i][0])<=b){
cout<<i;
return 0;
}
}
}
/*
6 16
10 9
10 5 1
12 2 1
20 18 3
10 2 3
2 1 5
*/

思路是对的,剪枝也剪了,像什么cnt【】,jj之类的,但是还是G了;
那再看看正经题解:

#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch;int x=0,f=1;
ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
const int N=5e3+10;
int n,b,f[N][N][2],cnt[N],w1[N],w[N],head[N],jcnt;
bool v[N];
struct jj{
int to,next;
}ed[N*2];
inline void add(int x,int y){
ed[++jcnt]={y,head[x]};
head[x]=jcnt;
}
inline void dfs(int x){
cnt[x]=1;
f[x][1][1]=w[x]-w1[x],f[x][1][0]=w[x];f[x][0][0]=0;
for(int p=head[x];p;p=ed[p].next){
int j=ed[p].to;
dfs(j);
for(int i=cnt[x];i>=0;i--){
for(int k=0;k<=cnt[j];k++){
f[x][i+k][1]=min(f[x][i+k][1],min(f[j][k][1],f[j][k][0])+f[x][i][1]);
f[x][i+k][0]=min(f[x][i+k][0],f[j][k][0]+f[x][i][0]);
}
}
cnt[x]+=cnt[j];
}
}
int main(){
n=read();b=read();
w[1]=read();w1[1]=read();
int z;
for(register int i=2;i<=n;i++){
w[i]=read();w1[i]=read();z=read();
add(z,i);
}
memset(f,0x3f,sizeof(f));
dfs(1);
for(register int i=n;i>=0;i--){
if(f[1][i][1]<=b||f[1][i][0]<=b){
cout<<i;
return 0;
}
}
}

首先让我最懊悔的一点:
jj这个剪枝,因为用了除法,所以导致出现了/0的情况,而且还没什么大用(非常好剪枝,让我的大脑疯狂旋转)。
其次:
这是这个题对于我来说最重要的一点:
可以看出题解中的DP是从前往后推过去的,而我的是从后往前利用前面逆推的,这就导致我的cnt数组其实每次都会多一些,而且我是提前算好的,没有具体划分每个儿子,而题解中划分了。不要看不起这一小点,如果不这么改还真的会大T特T。
逆天

第二题说完了。
然后这最后一题吧,额,只能说是跟屎一样出的非常的好,非常的具有挑战性,非常的具有前瞻性啊,上来一看题解是0/1分数规划直接就给我整不会了。
这个得分率也是非常的人性化,最高分20分,纯拿单调队列一遍一遍扫的,也有的可以特判大样例骗到5分。全场只有4个20的和一个10的。

posted @   lzrG23  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示