zoukankan      html  css  js  c++  java
  • CF Round #635 div2 题解

    (Codeforces) (Round) (635)

    A. Ichihime and Triangle

    (Description:)

    给定四个整数(a,b,c,d),找到三个整数(x,y,z)满足(aleq xleq bleq yleq cleq zleq d)
    使得(x,y,z)能构成三角形

    (Solution:)

    签到题,直接令(x=b,y=c,z=)c即可,小边尽可能大,大边尽可能小

    (Code:)

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		int a,b,c,d;
    		scanf("%d%d%d%d",&a,&b,&c,&d);
    		printf("%d %d %d
    ",b,c,c);
    	}
    	return 0;
    }
    

    B. Kana and Dragon Quest game

    (Description:)

    一条龙有(h)的生命值,你总共有两种技能可以释放:
    1.将龙的血量变为(lfloor frac{h}{2} floor+10)
    2.将龙的血量变为(h-10)
    已知第一个技能可以用(n)次,第二个技能可以用(m)次,请问能否打败巨龙

    (Solution:)

    我的做法是(dp)
    (f[i][j])表示用(1)技能(i)次,用(2)技能(j)次后龙的最小血量
    跑完(dp)之后扫一遍看有没有(0)出现即可

    (Code:)

    #include<bits/stdc++.h>
    using namespace std;
    int t,h,n,m,f[35][35];
    int main(){
    	int i,j;
    	scanf("%d",&t);
    	while(t--){
    		memset(f,0x3f,sizeof(f));
    		scanf("%d%d%d",&h,&n,&m);
    		f[0][0]=h;
    		for(i=0;i<=n;i++){
    			for(j=0;j<=m;j++){
    				if(i<n)f[i+1][j]=max(0,min(f[i+1][j],f[i][j]/2+10));
    				if(j<m)f[i][j+1]=max(0,min(f[i][j+1],f[i][j]-10));
    			}
    		}
    		bool flag=0;
    		for(i=0;i<=n;i++)
    			for(j=0;j<=m;j++)
    				if(f[i][j]==0)flag=1;
    		if(flag)printf("YES
    ");
    		else printf("NO
    ");
    	}
    	return 0;
    }
    

    C. Linova and Kingdom

    (Description:)

    给你一棵以(1)为根节点的树,你可以在这棵树上设定(k)个关键节点
    使得所有非关键节点到根的路径上关键节点数的总和最大
    求出这个最大值

    (Solution:)

    手算几组数据之后发现在最优的情况下,如果一个节点是关键节点,那么它的父节点也是关键节点
    那么此时增加一个关键节点所获得的收益就是(size_i-depth_i)
    其中(size)为以(i)为根节点的子树的大小,(depth)(i)的深度
    我们直接一个(dfs)处理出(size)(depth),然后排序统计答案即可

    (Code:)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long lol;
    int n,m,head[200005],size;
    struct node{
    	int to,next;
    }edge[500005];
    struct point{
    	int x,son,depth;
    }p[200005];
    void putin(int from,int to){
    	size++;
    	edge[size].to=to;
    	edge[size].next=head[from];
    	head[from]=size;
    }
    void dfs(int r,int fa,int dep){
    	int i;
    	p[r].son=1;p[r].depth=dep;
    	for(i=head[r];i!=-1;i=edge[i].next){
    		int j=edge[i].to;
    		if(j!=fa){
    			dfs(j,r,dep+1);
    			p[r].son+=p[j].son;
    		}
    	}
    }
    bool cmp(const point a,const point b){
    	return a.son-a.depth>b.son-b.depth;
    }
    int main(){
    	int i,j;
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);m=n-m;
    	for(i=1;i<n;i++){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		putin(u,v);
    		putin(v,u);
    	}
    	for(i=1;i<=n;i++)p[i].x=i;
    	dfs(1,0,1);
    	sort(p+1,p+n+1,cmp);
    	lol ans=0;
    	for(i=1;i<=m;i++)
    		ans+=p[i].son-p[i].depth;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    D. Xenia and Colorful Gems

    (Description:)

    给定三个数列,在每个数列中分别选取一个数(x,y,z)
    使得((x-y)^+(y-z)^2+(x-z)^2)最小,并输出这个最小值

    (Solution:)

    先把三个数列排序,然后让(i,j,k)分别指向三个数列的最小值
    再贪心的选取(i,j,k)中的(+1),使得变化后的((x-y)^+(y-z)^2+(x-z)^2)最小
    不是很懂这个贪心策略为什么是对的,比赛的时候也只是碰碰运气,结果莫名其妙的对了
    显然正解因该是枚举第一个数列的数,然后对另外连个数列进行二分查找

    (Code:)

    #include<bits/stdc++.h>
    #define inf (9223372036854775807)
    using namespace std;
    typedef long long lol;
    int t,A,B,C;
    lol a[100005],b[100005],c[100005];
    lol cal(int i,int j,int k){
    	return (a[i]-b[j])*(a[i]-b[j])+(b[j]-c[k])*(b[j]-c[k])+(a[i]-c[k])*(a[i]-c[k]);
    }
    int main(){
    	int i,j,k;
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d%d",&A,&B,&C);
    		for(i=1;i<=A;i++)scanf("%lld",&a[i]);
    		for(i=1;i<=B;i++)scanf("%lld",&b[i]);
    		for(i=1;i<=C;i++)scanf("%lld",&c[i]);
    		sort(a+1,a+A+1);
    		sort(b+1,b+B+1);
    		sort(c+1,c+C+1);
    		i=1;j=1;k=1;
    		lol ans=inf;
    		while(i<=A&&j<=B&&k<=C){
    			lol tmp=cal(i,j,k),sum1=i<A?cal(i+1,j,k):inf,sum2=j<B?cal(i,j+1,k):inf,sum3=k<C?cal(i,j,k+1):inf;
    			ans=min(ans,tmp);
    			sum1=sum1-tmp;sum2=sum2-tmp;sum3=sum3-tmp;
    			if(sum1<=sum2&&sum1<=sum3)i++;
    			else if(sum2<=sum1&&sum2<=sum3)j++;
    			else if(sum3<=sum1&&sum3<=sum2)k++;
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    E. Kaavi and Magic Spell

    (Description:)

    给定两个字符串(s,t),现在你有一个空串(a),每次操作可以将(s)的首字母提取出来并放在(a)的最前面或者最后面
    操作过程中使得(a)的前缀是(t)的情况有多少种

    (Solution:)

    显然(lentleq lens),我们不妨将(t)拓展到和(s)一样长,其中拓展的一部分可以是任意字母
    定义状态(f[l][r])表示当前状态下,操作过程中a的前缀为(t_lsim t_r)的情况数
    外层循环遍历(s),枚举当前要添加的字母,那么
    如果当前枚举到的(s_i=t_r),那么(f[l][r]=f[l][r]+f[l][r-1])
    特别注意的是,由于(t)的延长部分可以为任何字母,所以一旦(r>lent),也要执行上述转移
    如果当前枚举到的(s_i=t_l),那么(f[l][r]=f[l][r]+f[l+1][r])
    特别注意的是,由于(t)的延长部分可以为任何字母,所以一旦(l>lent),也要执行上述转移
    最后统计以下(f[1][lentsim lens])的和即可

    (Code:)

    #include<bits/stdc++.h>
    #define mod (998244353)
    using namespace std;
    char s[3005],t[3005];
    int lens,lent,f[3005][3005];
    int main(){
    	int i,j,len;
    	scanf("%s%s",s+1,t+1);
    	lens=strlen(s+1);lent=strlen(t+1);
    	for(i=1;i<=lens+1;i++)f[i][i-1]=1;
    	for(i=1,len=1;i<=lens;i++,len++){
    		for(int l=1,r=l+len-1;r<=lens;l++,r++){
    			if(l>lent||s[i]==t[l])f[l][r]=(f[l][r]+f[l+1][r])%mod;
    			if(r>lent||s[i]==t[r])f[l][r]=(f[l][r]+f[l][r-1])%mod;
    		}
    	}
    	int ans=0;
    	for(i=lent;i<=lens;i++)
    		ans=(ans+f[1][i])%mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    

    BBT

    运气比较好吧,有几个结论是猜对的。
    但是还是被自己菜到:
    (T2)明明是个数学题,偏偏要去整什么dp,简直就是耽误比赛时间。。。
    (T3)交的时候手抖选错编译器,编译错误一次,简直是在搞笑,改完之后还没有一遍过,菜的不行。。。
    (T4)那么简单的二分查找想不到,非要去整一个自己都不确定的贪心。。。不过还好,蒙对了(手动狗头)

  • 相关阅读:
    常见面试题1
    勒索病毒防范方法
    VMware虚拟机打开后不兼容
    win10桌面显示我的电脑设置
    scala集合和Java集合对应转换操作
    scala中使用redis
    爬虫调研
    hadoop命令
    IDEA打jar包
    spark.mllib
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/12715471.html
Copyright © 2011-2022 走看看