• CDZSC_2022寒假个人训练赛21级(10)题解


    • 简单
      • D 枚举、dp、数学
      • G 素数
    • 中等
      • A
      • B dfs
      • E 模拟、数学
      • F 贪心
    • 困难
      • C 构造
      • H 整数的唯一分解定理+约数和定理+递归二分求等比数列+快速幂

    A Visiting a Friend CodeForces - 902A

    题意

    在数轴上你从0点出发,要到达m点,只能通过传送点移动,传送点给你一对a,b,a代表传送点的位置,b代表最远可以传送的长度。问你能不能到m点。

    题解

    首先因为只能通过传送点移动,0点必须有传送点,然后为了能到达m点,0点到m点之间必须被传送段完全覆盖,至于实现,只要维护一个目前能达到的最远距离就好。

    AC代码

    #include<iostream>
    using namespace std;
    int main(){
    	int n,m,a,b,r=0,flag=0;
    	scanf("%d%d",&n,&m);
    	for(int i=0;i<n;i++){
    		scanf("%d%d",&a,&b);
    		if(a==0)flag=1;
    		if(a<=r)r=r>b?r:b;
    	}
    	if(r<m)flag=0;
    	printf("%s\n",flag?"YES":"NO");
    	return 0;
    }
    

    B Coloring a Tree CodeForces - 902B

    题意

    给你颗树,每一次可以选择一个子树全染成一种颜色,问你要染成要求的颜色最少要多少步。

    题解

    因为染子树,所以上面染完必然会覆盖下面的,从根到叶dfs遍历,父节点和子节点要求颜色不同的最终答案就加1,根节点要染一次所以额外还要加一次,我下面的写法是用了一个假父节点0来方便的处理这个问题的。

    AC代码

    #include<iostream>
    #include<algorithm>
    #include<vector>
    
    using namespace std;
    vector<int> e[100005];
    int v[100005];
    int ans;
    void dfs(int x, int f) {
    
    	for (auto i : e[x]) {
    		if (i != f) {
    			if (v[i] != v[x])ans++;
    			dfs(i, x);
    
    		}
    	}
    
    }
    
    int main() {
    	int n, x;
    	scanf("%d", &n);
    
    	for (int i = 2; i <= n; i++) {
    		scanf("%d", &x);
    		e[i].emplace_back(x);
    		e[x].emplace_back(i);
    	}
    
    	for (int i = 1; i <= n; i++) {
    		scanf("%d", &x);
    		v[i] = x;
    
    	}
    	ans++;
    	dfs(1, 0);
    	printf("%d\n", ans);
    	return 0;
    }
    
    

    C Hashing Trees CodeForces - 902C

    题意

    给出一颗n层的树。以及从第0层开始给出每层的节点个数。求是否存在同构,若存在输出“ambiguous”和 2 个可以同构的树,如果不可以输出“perfect”。

    题解

    很容易知道,只要相邻的两层节点数都大于1就一定有同构。

    AC代码

    #include<iostream>
    
    using namespace std;
    
    int s[100005];
    int p[200005];
    int main(){
    	int n;
    	scanf("%d",&n);
    	int flag=0;
    	for(int i=0;i<=n;i++){
    		scanf("%d",s+i);
    		if(i&&s[i]>1&&s[i-1]>1) {
    			flag=i;
    		}
    	}
    	if(!flag){
    		printf("perfect\n");
    		scanf(" ");
    		return 0;
    	}
    	int f=0;
    	for(int i=0;i<=n;i++){
    		int x=f;
    		while(f-x<s[i])p[f++]=x;
    		if(i&&s[i]>1&&s[i-1]>1) {
    			flag=f-1;
    		}
    	}
    	
    	printf("ambiguous\n");
    	for(int i=0;i<f;i++)
    		printf("%d ",p[i]);
    	printf("\n");
    	for(int i=0;i<f;i++){
    		if(i==flag)p[i]--;
    		printf("%d ",p[i]);
    	}
    	printf("\n");
    
    	scanf(" ");
    	return 0;
    }
    

    D Hungry Student Problem CodeForces - 903A

    题意

    \(T\)次询问,每次问有没有两个非负整数\(x,y\)使得\(3*x + 7*y = n\)

    题解

    数据很小怎么做都行。

    • 方法一:两个for暴力x,y
    • 方法二:dp,其实和背包差不多
    • 方法三:数学方法,其实这种互质的组成数的问题,只要大于一定的数字就一定可以组成所有数,比如这个的3和7,实际上大于11一定有解。

    AC代码

    //方法二
    #include<iostream>
    using namespace std;
    int dp[200];
    int main() {
    	int n, x;
    	dp[0] = 1;
    	for (int i = 3; i <= 100; i++) 
    		dp[i] = dp[i - 3] ? 1 : dp[i];
    	for (int i = 7; i <= 100; i++)
    		dp[i] = dp[i - 7] ? 1 : dp[i];
    
    	scanf("%d", &n);
    
    	while (n--) {
    		scanf("%d", &x);
    		printf("%s\n", dp[x] ? "YES" : "NO");
    	}
    }
    
    //方法三
    #include<iostream>
    using namespace std;
    int ans[105]={1,1,1,0,1,1,0,0,1,0,0,1};
    int main() {
    	int n,x;
    	
    	scanf("%d", &n);
    
    	while (n--) {
    		scanf("%d", &x);
    		printf("%s\n",!ans[x] ? "YES" : "NO");
    	}
    }
    

    E The Modcrab CodeForces - 903B

    题意

    一个人在打怪,他每回合可以选择喝药加血或者打怪,然后怪物会攻击他一次,让你输出一个他可以打死怪物的方案(任意一个即可,特殊判定),但是注意他的血量可以无上限。第一行输入他的当前血量h1,攻击力a1,药每次回复c的血量,第二行输入怪物的血量h2,怪物的攻击力a2,。

    题解

    由于你回血量一定高于攻击力,所以,一直打怪,如果下一次要被杀死了,再回血就好,当然先把血回到可以杀死怪物的状态也行,那样可能还会更快点,但反正数据范围很小,随便做。

    AC代码

    #include<iostream>
    using namespace std;
    int p[10500];
    int main() {
    	int h1, h2, a1, a2, c,k=0;
    	scanf("%d%d%d%d%d", &h1,&a1,&c,&h2,&a2);
    	while (h2 > 0) {
    		if (h2 - a1 <= 0) {
    			p[k] = 1;
    			h2 -= a1;
    		}
    		else if (h1 - a2 > 0) {
    			p[k] = 1;
    			h2 -= a1;
    		}
    		else h1 += c;
    		k++;
    		h1 -= a2;
    	}
    	printf("%d\n", k);
    	for (int i = 0; i < k; i++) {
    		printf("%s\n", p[i] ? "STRIKE" : "HEAL");
    	}
    }
    
    #include<iostream>
    
    using namespace std;
    
    int main() {
    	int h1, h2, a1, a2, c1;
    	scanf("%d%d%d", &h1, &a1, &c1);
    	scanf("%d%d", &h2, &a2);
    	int n = (h2 + a1 - 1) / a1;//需要攻击几次
    
    	int h = (n-1) * a2+1; //需要多少血
    	int m = (h - h1 + (c1 - a2 - 1)) / (c1 - a2);//需要回几次血
    	if (m < 0)m = 0;
    	printf("%d\n", n + m);
    	for (int i = 0; i < m; i++)
    			printf("HEAL\n");
    	for (int i = 0; i < n; i++)
    		printf("STRIKE\n");
    }
    
    

    F Boxes Packing CodeForces - 903C

    题意

    给你n个盒子,把小盒子放进大的盒子里,这样只能看到大盒子,输出最小能够有看到的盒子数。

    题解

    贪心,可以看成小的盒子替换大的盒子,因为如果大盒子套个小的,那那个大盒子能继续套的只能是比那个小盒子还小的盒子了。排序后找第一个比自己小的嵌套。

    AC代码

    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int s[5005];
    int main(){
    	int n;
    	while(~scanf("%d",&n)){
    		for(int i=0;i<n;i++)
    			scanf("%d",s+i);
    		sort(s,s+n);
    		int j=n-1;
    		for(int i=j-1;i>=0;i--)
    			if(s[i]<s[j])
    				j--;
    
    		printf("%d\n",j+1);
    	}
    	scanf(" ");
    	return 0;
    }
    

    G 结果填空:有趣的数字 计蒜客 - 43115

    题解

    直接输出结果就好,数据范围很小,又是直接输入结果的题,所以实际上连素数筛都不用,暴力,哪怕是最差的\(O(n^2)\)复杂度的暴力都能过,就是要挂机跑一会。我下面是一个优化的暴力,复杂度为\(O(n\sqrt{n})\),筛法我就不写了,大家应该都会吧,欧拉筛和埃式筛都行。
    \(O(n^2)\)复杂度的暴力我电脑跑十几秒也出了)

    AC代码

    #include<iostream>
    
    using namespace std;
    int main() {
    	// int ans = 0;
    	// for (int i = 2; i <= 100000; i++) {
    	// 	int flag = 1;
    	// 	for (int j = 2; j*j <= i; j++) {
    	// 		if (i%j == 0) {
    	// 			flag = 0;
    	// 		}
    
    	// 	}
    	// 	if (flag) {
    	// 		int x = i;
    	// 		while (x) {
    	// 			if (x % 10 == 5) {
    	// 				ans++;
    	// 				break;
    	// 			}
    	// 			x /= 10;
    	// 		}
    	// 	}
    
    	// }
    	// printf("%d\n", ans);
    	
    	printf("3282");
    }
    
    

    H Sumdiv OpenJ_Bailian - 1845

    题意

    \(A^B\)的约数和对9901取余的结果。

    题解

    使用约数和定理求值,具体实现用递归二分求,求值的时候有大指数,使用快速幂解决。

    AC代码

    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    typedef long long ll;
    
    ll p[100005], c[100005];
    
    ll pow(ll x, ll y,ll mod) {
    	ll ans = 1%mod;
    	while (y) {
    		if (y & 1)ans = (ans*x) % mod;
    		x = (x*x) % mod;
    		y >>= 1;
    	}
    	return ans;
    }
    int k[105];
    ll sum(ll p, ll c,ll mod) {
    	if (c == 0)return 1;
    	if (c == 1)return (1 + p) % mod;
    	if (c % 2)return ((1 + pow(p, (c + 1) / 2, mod))*sum(p, (c - 1) / 2,mod))%mod;
    	else return ((1 + pow(p, c / 2,mod))*sum(p, c / 2 - 1,mod) + pow(p, c,mod)) % mod;
    }
    
    int main() {
    	ll a, b;
    	ll  mod = 9901;
    	scanf("%lld%lld", &a, &b);
    	int m=0;
    
    	for (int i = 2; i*i <= a; i++) {
    		if (a%i == 0) {
    			p[m] = i;
    			c[m] = 0;
    			while (a%i == 0) {
    				a /= i;
    				c[m]++;
    			}
    			m++;
    		}
    	} if (a != 1) {
    		p[m] = a;
    		c[m++] = 1;
    	}
    	ll ans = 1;
    	for (int i = 0; i < m; i++) {
    
    		ans = (ans*sum(p[i], c[i] * b,mod)) % mod;
    	}
    	printf("%lld\n", ans);
    
    }
    
  • 相关阅读:
    React教程(一) React介绍与搭建
    微信公众号订阅号以及服务号通过网页授权获取用户openid方法
    AES,DES加密JS源文件及其使用方法
    R 分类进行数值处理
    C++ const 关键字总结
    软工lintcode作业
    [恶意软件分析]DroidBox的环境搭建与使用
    Android第三次作业
    Android第二次作业
    android 第一次作业
  • 原文地址:https://www.cnblogs.com/komet/p/15906570.html
Copyright © 2020-2023  润新知