首页 > 其他分享 >Atcoder DP Contest

Atcoder DP Contest

时间:2024-10-30 11:22:20浏览次数:6  
标签:std Atcoder include Contest int 100001 using main DP

好像都在说这套题很好,所以来刷一遍

太水的就只放代码了

尚未完工,先发一下

猫猫可爱捏 https://www.tldraw.com/ro/1g8hQBpWTkduIlFxT3c0P?d=v-1275.1523.960.968.page

A.Frog 1

#include<bits/stdc++.h>
using namespace std;
int n;
int h[100001];
int f[100001];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&h[i]);
	}
	memset(f,0x3f,sizeof f);
	f[1]=0;
	for(int i=1;i<=n;++i){
		if(i+1<=n) f[i+1]=min(f[i+1],f[i]+abs(h[i]-h[i+1]));
		if(i+1<=n) f[i+2]=min(f[i+2],f[i]+abs(h[i]-h[i+2]));
	}
	cout<<f[n]<<endl;
}

B.Frog 2

#include<bits/stdc++.h>
using namespace std;
int n,k;
int h[100001];
int f[100001];
int main(){
	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;++i){
		scanf("%d",&h[i]);
	}
	memset(f,0x3f,sizeof f);
	f[1]=0;
	for(int i=1;i<=n;++i){
		for(int j=i+1;j<=i+k;++j){
			if(j<=n) f[j]=min(f[j],f[i]+abs(h[i]-h[j]));
		}
	}
	cout<<f[n]<<endl;
}

C.Vacation

#include<bits/stdc++.h>
using namespace std;
int n;
int a[100001],b[100001],c[100001];
int f[100001][3];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d %d %d",&a[i],&b[i],&c[i]);
	}
	for(int i=1;i<=n;++i){
		f[i][0]=max(f[i-1][1],f[i-1][2])+a[i];
		f[i][1]=max(f[i-1][0],f[i-1][2])+b[i];
		f[i][2]=max(f[i-1][1],f[i-1][0])+c[i];
	}
	cout<<max({f[n][0],f[n][1],f[n][2]});
} 

D.Knapsack 1

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
int w[101],v[101];
int f[2][100001];
int ans=0;
signed main(){
	scanf("%lld %lld",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%lld %lld",&w[i],&v[i]);
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			f[i&1][j]=f[(i-1)&1][j];
		}
		for(int j=w[i];j<=m;++j){
			f[i&1][j]=max(f[i&1][j],f[(i-1)&1][j-w[i]]+v[i]);
			ans=max(ans,f[i&1][j]);
		}
	}
	cout<<ans;
}

E.Knapsack 2

这题还挺有意思的,就是一个简单背包,但是背包容量在 \(10^9\) 级别,正常做无论空间还是时间都会寄掉

但是 \(N\le 100\),且单个物品权值在 \(10^4\) 以内,算了一下总和也只有 \(10^6\),应该是想让开这一维

所以设 \(f_{i,j}\) 表示考虑前 \(i\) 个物品,价值总和为 \(j\) 的花费容量最小值(这种类似的状态设计看的不少了,也是挺重要的一类 DP)

然后直接转移就行

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
int w[101],v[101];
int f[2][100000];
int ans=0;
int sumv;
signed main(){
	scanf("%lld %lld",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%lld %lld",&w[i],&v[i]);
		sumv+=v[i];
	}
	memset(f,0x3f,sizeof f);
	f[0][0]=0;
	for(int i=1;i<=n;++i){
		for(int j=0;j<=sumv;++j){
			f[i&1][j]=f[(i-1)&1][j];
		}
		for(int j=v[i];j<=sumv;++j){
			f[i&1][j]=min(f[i&1][j],f[(i-1)&1][j-v[i]]+w[i]);
			if(f[i&1][j]<=m){
				ans=max(ans,j);
			}
		}
	}
	cout<<ans<<endl;
}

F.LCS

最长公共子序列板子,还是 \(n^2\) 级别的,一眼水题

这道题输出路径比较有启发意义,一开始不会写,单独开了一个 pair 数组记录前驱,虽然这样也能做,但是很麻烦

记录前驱的写法
#include<bits/stdc++.h>
using namespace std;
string s,t;
int f[3001][3001];
pair<int,int> path[3001][3001];
int ans=0;
int ansi,ansj;
int main(){
	cin>>s>>t;
	s="."+s;t="."+t;
	for(int i=1;i<=(int)s.length()-1;++i){
		for(int j=1;j<=(int)t.length()-1;++j){
			if(f[i][j-1]>f[i-1][j]) path[i][j]=path[i][j-1];
			else path[i][j]=path[i-1][j];
			f[i][j]=max(f[i][j-1],f[i-1][j]);
			if(f[i-1][j-1]+(s[i]==t[j])>f[i][j]){
				f[i][j]=f[i-1][j-1]+(s[i]==t[j]);
				path[i][j]={i-1,j-1};
			}
			if(ans<f[i][j]){
				ans=f[i][j];
				ansi=i;ansj=j;
			}
		}
	}
	string anss;
	int cnt=0;
	while(ansi and ansj){
		if(cnt==ans) break;
		pair<int,int>x=path[ansi][ansj];
		ansi=x.first;ansj=x.second;
		anss.push_back(s[ansi+1]);
		cnt++;
	}
	reverse(anss.begin(),anss.end());
	cout<<anss<<endl;
}

去题解区翻了一下,其实输出路径可以从 DP 数组里倒着往回找,比如你要找最后一位的答案,只需要从 \(f_{i,j}=f_{n,m}\) 的 \((i,j)\) 里面找一个 \(s_i=t_j\) 的位置,这一点开个双指针就能做

否则,如果 \(f_{i,j}\) 和 \(f_{i-1,j}/f_{i,j-1}\) 一样,意味着这一位没啥大用,可以直接跳过去

#include<bits/stdc++.h>
using namespace std;
string s,t;
int f[3001][3001];
int ans=0;
int ansi,ansj;
int main(){
	cin>>s>>t;
	s="."+s;t="."+t;
	for(int i=1;i<=(int)s.length()-1;++i){
		for(int j=1;j<=(int)t.length()-1;++j){
			f[i][j]=max(f[i][j-1],f[i-1][j]);
			f[i][j]=max(f[i][j],f[i-1][j-1]+(s[i]==t[j]));
		}
	}
	string anss;
	int i=(int)s.length()-1,j=(int)t.length()-1;
	while(f[i][j]!=0){
		if(s[i]==t[j]){
			anss.push_back(s[i]);
			i--;j--;
		}
		else{
			if(f[i][j]==f[i-1][j]) i--;
			else j--;
		}
	}
	reverse(anss.begin(),anss.end());
	cout<<anss<<endl;
}

G.Longest Path

拓扑一遍即可

#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int>e[100001];
int f[100001];
int inde[100001];
bool vis[100001];
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;++i){
		int x,y;scanf("%d %d",&x,&y);
		e[x].push_back(y);
		inde[y]++;
	}
	queue<int>q;
	for(int i=1;i<=n;++i){
		if(inde[i]==0){
			q.push(i);
		}
	}
	int ans=0;
	while(!q.empty()){
		int u=q.front();q.pop();
		if(vis[u]) continue;
		vis[u]=true;
		for(int i:e[u]){
			if(!vis[i]){
				inde[i]--;
				f[i]=max(f[i],f[u]+1);
				ans=max(ans,f[i]);
				if(inde[i]==0){
					q.push(i);
				}
			}
		}
	}
	cout<<ans;
} 

H.Grid 1

#include<bits/stdc++.h>
using namespace std;
const int p=1e9+7;
int n,m;
char mp[1001][1001];
int f[1001][1001];
char getchar(const vector<char>&A){
	char ch=getchar();
	while(1){
		for(char i:A) if(i==ch) return i;
		ch=getchar();
	}
}
int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			mp[i][j]=getchar({'.','#'});
		}
	}
	f[1][1]=1;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if((i!=1 or j!=1) and mp[i][j]!='#'){
				if(i!=1 and mp[i-1][j]!='#') f[i][j]=(f[i][j]+f[i-1][j])%p;
				if(j!=1 and mp[i][j-1]!='#') f[i][j]=(f[i][j]+f[i][j-1])%p;
			}
		}
	}
	cout<<f[n][m];
} 

I.Coins

还是看看远处的记搜把家人们

#include<bits/stdc++.h>
using namespace std;
int n;
long double p[3000];
long double f[3001][3001];
long double dfs(int now,int poscnt){
	if(now>n){
		int negcnt=n-poscnt;
		if(poscnt>negcnt) return 1;
		return 0;
	}
	if(f[now][poscnt]>=0) return f[now][poscnt];
	return f[now][poscnt]=dfs(now+1,poscnt+1)*p[now]+dfs(now+1,poscnt)*(1-p[now]);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		for(int j=0;j<=n;++j){
			f[i][j]=-1;
		}
		scanf("%Lf",&p[i]);
	}
	printf("%.20Lf",dfs(1,0));
} 

J.Sushi

苏轼

不愧是苏轼,给我整不会了

记搜,首先你可以注意到,剩余sushi相同的盘子是等价的

又因为这个题值域只有四种情况,因此可以直接考虑开桶

设计 \(f_{i,j,k}\) 分别表示剩余 \(1,2,3\) 个sushi的盘子数量,剩余 \(0\) 个的情况可以通过 \(n-i-j-k\) 算出

然后直接转移就好了,唯一的问题是怎么考虑不拿的情况

显然你不能直接搜下去,而是应该考虑这些不拿的次数在平均情况下会造成多少贡献(因为你不管在何种状态下,最终都要靠下面三种情况来转移状态,也就是不管咋整都得加上这些期望,你可以直接把不拿的作为一个基础概率加上)

还是根据经典结论,如果一件事发生的概率为 \(m\),你需要靠平均 \(\frac{1}{m}\) 次才能使其发生

这里显然要求的就是 “选到一个还有 sushi 的盘子” 的发生概率,显然是 \(\frac{i+j+k}{n}\),取个倒数就是基础概率

#include<bits/stdc++.h>
using namespace std;
int n;
int a[301];
int cnt[4];
double f[301][301][301];
double dfs(int cnt1,int cnt2,int cnt3){
	int tot=cnt1+cnt2+cnt3;
	if(tot==0) return 0;
	if(f[cnt1][cnt2][cnt3]>=0) return f[cnt1][cnt2][cnt3];
	double res=n*1.0/tot;
	if(cnt1) res+=dfs(cnt1-1,cnt2,cnt3)*cnt1/tot;
	if(cnt2) res+=dfs(cnt1+1,cnt2-1,cnt3)*cnt2/tot;
	if(cnt3) res+=dfs(cnt1,cnt2+1,cnt3-1)*cnt3/tot;
	return f[cnt1][cnt2][cnt3]=res;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		cnt[a[i]]++;
	}
	for(int i=0;i<=n;++i){
		for(int j=0;j<=n;++j){
			for(int k=0;k<=n;++k){
				f[i][j][k]=-1;
			}
		}
	} 
	printf("%.20lf",dfs(cnt[1],cnt[2],cnt[3]));
}

K.Stones

标签:std,Atcoder,include,Contest,int,100001,using,main,DP
From: https://www.cnblogs.com/HaneDaCafe/p/18515004

相关文章

  • 01背包问题(经典dp题解)
    有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 ii 件物品的体积是 vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。输入格式第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。接下来......
  • 【linux网络编程】| socket套接字 | 实现UDP协议聊天室
        前言:本节内容将带友友们实现一个UDP协议的聊天室。主要原理是客户端发送数据给服务端。服务端将数据再转发给所有链接服务端的客户端。所以,我们主要就是要实现客户端以及服务端的逻辑代码。那么,接下来开始我们的学习吧。    ps:本节内容建议了解so......
  • 2024.10.24 The 2021 ICPC Northwestern Russia Regional Contest
    比赛链接Solved:8/14Penalty:909Rank:23前五道签到题ABCHL。K.KaleidoscopicRoute题意给一张带边权的图,求一条1到n的路径,使经过的边数最少的同时边的极差最大。题解求出最短路图,然后DAG上dp:f和g分别表示从1到这个点能经过的最大边权和最小边权。然后每转移一条边(x,y,z......
  • 2024.10.4 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest
    比赛链接Solved:7/11Penalty:914Rank:1/74Rank(vp):63/1k+Dirt:22%G答案是4*纯色块数+5。考虑怎么维护这个纯色块数。这道题的修改保证了一个块纯色当且仅当其行列都纯色。因此对行列分别维护一棵线段树,维护每一层分别有多少个纯色节点,按层乘起来相加就行。K1操作的增加量......
  • 2024.10.3 2022-2023 ICPC Brazil Subregional Programming Contest
    比赛链接Solved:12/14Rank:5/1k+Rank(vp):49/2k+Penalty:1619Dirt:45%前10个题都比较简单/套路。L做法很好想。但是……因为不会写启发式合并卡了40min,警钟长鸣!intsum[N];map<int,int>col[N];intsz[N];llnow[N],ans[N];voidmrg(intx,inty){x=find(x),y=fi......
  • [CSP-J 2022] 上升点列(DP)
    题目传送门解题思路首先先讲这些点按照  从小到大排序。然后,很容易想到设  表示到第  个点已经放了  个点的最长上升序列的长度。所以,我们可以从前面的点转移(注意要判断一下 是否符合,因为我们只按照了 排序);于是,手推一下可以整出这样一个转移方程:其中  是......
  • ScheduledThreadPoolExecutor的介绍与使用
    ScheduledThreadPoolExecutor是Java中的一个类,它继承自ThreadPoolExecutor,并实现了ScheduledExecutorService接口。这个类主要用于在给定的延迟之后或周期性地执行任务,是处理定时任务的一个强大工具。一、主要特点线程池大小固定:ScheduledThreadPoolExecutor的线程池大小......
  • AtCoder Beginner Contest 366 - VP记录
    A-Election2高桥日常出镜,kkk好好学学。点击查看代码#include<cstdio>usingnamespacestd;intmain(){ intn,t,a; scanf("%d%d%d",&n,&t,&a); if(t>n-t||a>n-a)printf("Yes\n"); elseprintf("No\n"); return0;......
  • STM32+致远电子Dport模块的Ethercat从站开发
    环境准备硬件环境1.Dport-stm32评估板2.stlink3.千兆网线4.安装有twincat3的上位机电脑(带千兆网口) 软件环境1.TC31-FULL-Setup.3.1.4024.53.exe2.mdk5开发环境3.SSCTool.exe4.stm32cubemx 例程资料1.致远电子官网 开发流程1.底层硬件EPC103-DP系统框图,......
  • AtCoder Beginner Contest 377
    上周六咕咕咕了省流版A.排序判断即可B.枚举判断即可C.记录覆盖位置去重,总数-覆盖数即可D.枚举右端点,考虑符合条件的左端点数量即可E.考虑排列的\(i\top_i\)图,考虑操作数与走的边数关系,利用环循环节算偏移量即可F.考虑每个皇后实际覆盖的位置,枚举先前皇后计算覆......