首页 > 编程语言 >第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京)

第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京)

时间:2022-11-03 13:24:47浏览次数:48  
标签:sz int void 45 ICPC ans 程序设计 calc dp

L Let's Play Curling

分析:

转换一下就是 找每两个b之间 最多有多少个a

先离散化 再树状数组维护一下就好

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=2e5+5;
int n,m,cnt,ans;
int a[maxn],b[maxn],t[maxn],tr[maxn];
void upd(int x){
	while(x<=maxn)tr[x]++,x+=lowbit(x);
}
int query(int x){
	int res=0;
	while(x)res+=tr[x],x-=lowbit(x);
	return res;
}
void solve();
int main(){
	int T;
	cin>>T;
	while(T--)solve();
     return 0;
}
void solve(){
	scanf("%d%d",&n,&m);
	ans=0;cnt=0;
	memset(tr,0,sizeof(tr));
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),t[++cnt]=a[i];
	for(int i=1;i<=m;i++)scanf("%d",&b[i]),t[++cnt]=b[i];
	b[0]=t[++cnt]=0,b[m+1]=t[++cnt]=1e9+7;
	sort(t+1,t+1+cnt);
	int len=unique(t+1,t+1+cnt)-t-1;
	for(int i=1;i<=n;i++){
		int id=lower_bound(t+1,t+1+len,a[i])-t;
		a[i]=id,upd(a[i]);
	}
	for(int i=0;i<=m+1;i++){
		int id=lower_bound(t+1,t+1+len,b[i])-t;
		b[i]=id;
	}
	sort(b,b+2+m);
	for(int i=1;i<=m+1;i++)
	ans=max(ans,query(b[i]-1)-query(b[i-1]));
	if(!ans)cout<<"Impossible"<<endl;
	else cout<<ans<<endl;
}

F.Fireworks

分析:

式子很好列出 关键在于我们担心计算的时候会掉精度 但是最后打出来貌似不会掉

注意点:因为是要求整数 但是三分只有在小数的时候才能准确找到峰值 所以三分整数最终需要判断+1和-1的值

同样也可以三分小数 最终在小数前后位置找

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
double n,m,p;
void solve();
double calc(int x){
	return (x*n+m)/(1-pow((10000-p)/10000,x));
}
int main(){
	int T;
	cin>>T;
	while(T--)solve();
     return 0;
}
void solve(){
	cin>>n>>m>>p;
	int l=1,r=1e9,ans;
	while(l<=r){
		int mid=(l+r)/2;
		int midd=(l+mid)/2;
		if(calc(mid)-calc(midd)>=1e-8)ans=midd,r=mid-1;
		else l=midd+1;
	}
	int res;
	if(calc(ans)-calc(ans-1)>=1e-8)res=ans-1;
	if(calc(ans)-calc(ans+1)>=1e-8)ans++;
	if(calc(ans)-calc(res)>=1e-8)ans=res;
	printf("%.6lf\n",calc(ans));
}

K Co-prime Permutation

签到题

E Evil Coordinate

分析:

很明显 只要障碍不在终点 或者只能朝x轴方向走(只能朝y轴方向走)并且一定会经过障碍点

其他情况一定是能构造出一个方案 使得路径不经过障碍点

分情况写起来很麻烦

题解给出了偷懒的智慧

完全用不着分类讨论

可以证明存在一种答案,使得相同的方向是连续排在一起的(按原字符串中有 1/2/3/4 种字母进行分类讨论)

枚举 UDLR 的 24 种排列即可

只要把所有情况都列出来 再判断即可

总结出经验 遇到分类讨论构造的题目 如果在数据范围允许的情况 可以遍历所有的构造方案

#include<bits/stdc++.h>
using namespace std;
int t,x,y,dx[]={0,0,-1,1},dy[]={1,-1,0,0},dd[200],c[4];
string s,ans,a="UDLR";
void solve()
{
	memset(c,0,sizeof c);
	scanf("%d%d",&x,&y);
	cin>>s;
	for(auto ch:s)c[dd[ch]]++;
	int xx=c[3]-c[2],yy=c[0]-c[1];
	if((xx==x&&yy==y)||(x==0&&y==0)){puts("Impossible");return;}
	int q[4]={0,1,2,3};
	do
	{
		xx=0,yy=0;
		ans="";
		for(int i=0;i<4;i++)
		{
			int p=q[i];
			for(int j=0;j<c[p];j++)
			{
				ans+=a[p];
				xx+=dx[p];
				yy+=dy[p];
				if(xx==x&&yy==y)goto End;
			}
		}
		cout<<ans<<endl;
		return;
		End:;
	}while(next_permutation(q,q+4));
	puts("Impossible");
}
int main()
{
	for(int i=0;i<4;i++)dd[a[i]]=i;
	scanf("%d",&t);
	while(t--)solve();
	return 0;
}

M Monster Hunter

分析:

很好分析的一道树形dp问题

因为相连点会造成影响 所以设置dp数组的时候多开一维 表示该点选择与否

dp[u][k][1] 表示u子树选择k个点 并且u选择的最小值

dp[u][k][0]表示u子树选择k个点 并且u不选择的最小值

不选择的点默认只能用魔法消掉

注意点:一开始一直觉得dfs里面两重循环会爆掉 但是实际上这个题目不会

在剪枝的条件下 具体复杂度肯定比三方小很多 比平方要大些

上下限都需要剪枝 不剪枝会TLE!!!!!!

总结一下就是:在n方的复杂度下是能够进行树上背包的 但是必须上下限都得剪枝

#include<bits/stdc++.h>
using namespace std;
int tot,g[2001],sz[2001],a[2001];
long long dp[2001][2001][2];
struct edge{
	int to,next;
}e[1000001];
void add(int a,int b)
{
	tot++;
	e[tot].to=b;
	e[tot].next=g[a];
	g[a]=tot;
}
void dfs(int x)
{
	sz[x]=1;
	dp[x][1][0]=a[x];
	dp[x][0][1]=0;
	for(int i=g[x];i;i=e[i].next)
	{
		dfs(e[i].to);
		sz[x]+=sz[e[i].to];
		for(int j=sz[x];j>=0;j--)
		{
			int di=max(0,j-sz[x]+sz[e[i].to]);//上下限都需要剪枝
			for(int k=min(j,sz[e[i].to]);k>=di;k--)
			{
				dp[x][j][0]=min(dp[x][j][0],dp[x][j-k][0]+min(dp[e[i].to][k][0]+a[e[i].to],dp[e[i].to][k][1]));
				dp[x][j][1]=min(dp[x][j][1],dp[x][j-k][1]+min(dp[e[i].to][k][0],dp[e[i].to][k][1]));
				//cout<<j<<" "<<k<<endl;
			}
		}
	}
}
signed main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n;
		scanf("%d",&n);
		for(int i=0;i<=n;i++)
		for(int j=0;j<=n;j++)
		dp[i][j][0]=dp[i][j][1]=1e18;
		for (int i=1;i<=n;i++)
		g[i]=0;tot=0;
		for(int i=2;i<=n;i++)
		{
			int x;scanf("%d",&x);
			add(x,i);
		}
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		dfs(1);
		for(int i=n;i>=0;i--)
		{
			printf("%lld ",min(dp[1][i][0],dp[1][i][1]));
		}
		puts("");
	}
	return 0;
} 	

标签:sz,int,void,45,ICPC,ans,程序设计,calc,dp
From: https://www.cnblogs.com/wzxbeliever/p/16854135.html

相关文章