Educational Codeforces Round 138 (Rated for Div. 2) A~D

比赛链接:Dashboard - Educational Codeforces Round 138 (Rated for Div. 2) - Codeforces 

目录

A. Cowardly Rooks

B. Death's Blessing

C. Number Game

D. Counting Arrays


A. Cowardly Rooks

题意:在n*n的棋盘中存在一些棋子,并且告诉你在同一行或者同一列不会出现两个棋子,请问能否将其中一个棋子换到另一个位置同样满足同一行或者同一列不会出现两个棋子。

思路:判断n>m即可,因为n*n的棋盘中有n个位置可以满足同一行或者同一列不会出现两个棋子的情况。

#define _CRT_SECURE_NO_WARNINGS 1
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<math.h>
#define FOR(a,b) for(int i=a;i<=b;i++)
#define ROF(a,b) for(int i=a;i>=b;i--)
#define FORj(a,b) for(int j=a;j<=b;j++)
#define ROFj(a,b) for(int j=a;j>=b;j--)
#define FORk(a,b) for(int k=a;k<=b;k++)
#define ROFk(a,b) for(int k=a;k>=b;k--)
#define mem(i,a) memset(i,a,sizeof(i))
#define ll long long
#define inf 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define int long long
#define yes cout<<"YES"<<endl
#define no cout<<"NO"<<endl
#define pi acos(-1.0)
#define endl '\n'
using namespace std;
const int maxn = 2e5 + 5;
void solve() {
	int n, m;
	cin >> n >> m;
	FOR(1, m) {
		int x, y;
		cin >> x >> y;
	}
	if (n >m)yes;
	else no;
}
signed main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);
	int _;
	cin >> _;
	while (_--)
		solve();
	return 0;
}

B. Death's Blessing

题意: 有n个怪物,怪物的属性有血量a[i]和死亡咒语b[i],当第i个怪物死亡时,它的邻居会增加b[i]的血量上限,杀死一个怪物的时间等于怪物的血量,请计算最快杀死所有怪物的时间。

思路:我们一定是在这行怪物的最左边或者最右边删除怪物,因为若不在最左边或者最右边删除怪物,那么怪物a[i]对应的b[i]会对总时间贡献两次b[i]的值,而在最左边或者最右边删除怪物,除了在最后删除的怪物,它们对总时间的贡献只有一次b[i](因为它们的左边或者右边没有怪物),并且最后一次删除怪物a[i]的b[i]是没有贡献的(因为它的左边和右边没有怪物),所以我们挑选b数组里最大的b[i]来使他没有贡献,同时其它的a[i]和b[i]提供一次贡献。

#define _CRT_SECURE_NO_WARNINGS 1
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<math.h>
#define FOR(a,b) for(int i=a;i<=b;i++)
#define ROF(a,b) for(int i=a;i>=b;i--)
#define FORj(a,b) for(int j=a;j<=b;j++)
#define ROFj(a,b) for(int j=a;j>=b;j--)
#define FORk(a,b) for(int k=a;k<=b;k++)
#define ROFk(a,b) for(int k=a;k>=b;k--)
#define mem(i,a) memset(i,a,sizeof(i))
#define ll long long
#define inf 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define int long long
#define yes cout<<"YES"<<endl
#define no cout<<"NO"<<endl
#define pi acos(-1.0)
#define endl '\n'
using namespace std;
const int maxn = 2e5 + 5;
int a[maxn]; 
void solve() {
	int sum=0,x,maxx=-1,n;
	cin>>n;
    FOR(1,n){
    	cin>>x;
    	sum+=x;
	}
	FOR(1,n){
		cin>>x;
		sum+=x;
		if(x>maxx)maxx=x;
	}
	cout<<sum-maxx<<endl;
}
signed main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);
	int _;
	cin >> _;
	while (_--)
		solve();
	return 0;
}

C. Number Game

题意: 给定一个长度为n的整数数组a, Alice和Bob玩游戏.

对于一个k, 游戏进行k轮, 第i轮,Alice选择从a中删除一个小于等于k - i + 1的数, Bob选择一个数加上k - i + 1.

如果某一轮Alice没有数字可以选择,则Bob赢,否则Alice赢.

问使得Alice赢的最大的k是多少?

思路:若Alice想赢的几率尽可能大,她应该选择满足小于等于k - i + 1的最大的数,因为这个数现在能选但是游戏的下一轮中却不一定能选(因为k-i+1在不断变小),而比这个更小的数下一轮还是能选,所以我们将适用回合最小但满足条件的数先用了,避免下一轮这个数不能用就浪费了。而若Bob想赢的几率尽可能大,他应该将Alice拥有最小的数变大,这样使当第k轮,Alice需要小于等于k - i + 1的数时,最小数比k - i + 1大,这样Alice就输了,使得Bob赢面更大。

因为a[i]的范围为1~100,所以直接模拟即可。

#define _CRT_SECURE_NO_WARNINGS 1
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<math.h>
#define FOR(a,b) for(int i=a;i<=b;i++)
#define ROF(a,b) for(int i=a;i>=b;i--)
#define FORj(a,b) for(int j=a;j<=b;j++)
#define ROFj(a,b) for(int j=a;j>=b;j--)
#define FORk(a,b) for(int k=a;k<=b;k++)
#define ROFk(a,b) for(int k=a;k>=b;k--)
#define mem(i,a) memset(i,a,sizeof(i))
#define ll long long
#define inf 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define int long long
#define yes cout<<"YES"<<endl
#define no cout<<"NO"<<endl
#define pi acos(-1.0)
#define endl '\n'
using namespace std;
const int maxn = 2e5 + 5;
int a[maxn],p[maxn];
void solve() {
	int n,ans=0,f;
	cin >> n;
	FOR(1, n)cin >> p[i];
	sort(p+ 1,p + n + 1);
	ROFk(n, 1) {
		for(int m=1; m<=n; m++)a[m]=p[m];
		FOR(1, k) {
			f = 0;
			ROFj(n, 1)if (a[j] <= k - i + 1&&a[j]) {
				a[j] = 0;
				f = 1;
				break;
			}
			if (f==0)break;
			FORj(1, n)if (a[i]){
				a[i] += k - i + 1;
				break;
			}
			sort(a + 1, a + n + 1);
		}
		if (f){
			ans = k;
			break;
		}
	}
	cout << ans << endl;
}
signed main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);
	int _;
	cin >> _;
	while (_--)
		solve();
	return 0;
}

D. Counting Arrays

题意: 对于一个数组a, 如果gcd(a[i],i)=1,就可以删掉第i个元素,删除后,重新编号(后面的往前移).

对于一个数组b,如果第i次能够删除a中第b[i]个位置, 则称b为a的可删除序列.

一个a称为歧义数组,如果它存在至少两个可删除序列.

现在给定n,m, 要求满足以下条件的歧义数组a的数目

  • a的长度小于等于n
  • a[i] <= m

思路 :若直接求歧义数组的数目会很难,但若我们反过来想,先求出无歧义数组的数目,再将总数目减去无歧义数组的数目,来得出有歧义数组的数目,这样便会简单很多。而无歧义数组的操作只有一种情况:每次只能删除下标为1的数组元素。所以我们构造无歧义数组。对于无歧义数组,每一位上的a[i],在2~i的范围内,他们gcd(a[i],i)!=1,所以a[i]就是2~i中所有出现过的质子之积的倍数,原因是一个数的因子里必须要有另一个数的全部质因子,才能令它们有不为1的公因子。

#define _CRT_SECURE_NO_WARNINGS 1
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<math.h>
#define FOR(a,b) for(int i=a;i<=b;i++)
#define ROF(a,b) for(int i=a;i>=b;i--)
#define FORj(a,b) for(int j=a;j<=b;j++)
#define ROFj(a,b) for(int j=a;j>=b;j--)
#define FORk(a,b) for(int k=a;k<=b;k++)
#define ROFk(a,b) for(int k=a;k>=b;k--)
#define mem(i,a) memset(i,a,sizeof(i))
#define ll long long
#define inf 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define int long long
#define yes cout<<"YES"<<endl
#define no cout<<"NO"<<endl
#define pi acos(-1.0)
#define endl '\n'
using namespace std;
const int maxn = 2e6 + 5;
const int mod=998244353;
bool pd(int x) {
	FOR(2,sqrt(x)) {
		if(x%i==0)return 0;
	}
	return 1;
}
void solve() {
	int n,m,cmp=1,ans=0,tot=1,del=1;
	cin >> n >> m;
	FOR(1,n) {
		if(pd(i)) cmp=cmp*i;//目前质因子的乘积
		tot=tot*(m%mod)%mod;//全部方案数
		ans=(ans+tot)%mod;//答案加上全部方案数 
		del=del*((m/cmp)%mod)%mod;//无歧义数目组合数 
		ans=(ans-del)%mod;//总答案为该数组长度所有的排列组合数减去无歧义序列数目
	}
	cout<<ans<<endl; 
}
signed main() {
	cin.tie(0);
	cout.tie(0);
	ios::sync_with_stdio(0);
	solve();
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值