Educational Codeforces Round 115 (Rated for Div. 2)

A. Computer Game(思维)

题意

给你一个 2 × n 2\times n 2×n的地图,然后你从左上角的位置往右下角移动,每次可以往八个方向前进一个单位,但是落脚点必须是0

思路

我们发现其实当第一行的第 i i i个元素和第二行的第 i i i个元素相等的时候并且等于1,那么就不能到达目的地

CODE

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int N = 1e5+10;

int t,n;

string mp[2];

int main()
{
	cin>>t;
	while(t--) {
		cin>>n;
		cin>>mp[0]>>mp[1];
		bool fg = true;
		for(int i = 0;i < n; ++i) {
			if(mp[0][i] == mp[1][i] && mp[0][i] == '1') fg = false;
		}
		if(fg) puts("YES");
		else puts("NO");	
	}
	
	return 0;
}

B. Groups(枚举)

题意

给你n(n为偶数)个学生的周内上课表,然后让你给这n个学生分为2组在不同的两天上课,问你能否满足有一种安排情况,使得两组的同学的人数相等

思路

首先,因为每个学生的上课时间是固定了的也就是5天,那么我们就直接枚举两天即可,注意两天不同

  • 我们统计两列信息的时候我们需要分别统计那天能上课的同学人数,以及都能上课的人数
  • 显然当都能上课的人数小于n的时候,那么就不满足了
  • 当左侧的同学人数和右侧的同学的人数都小于 n / 2 n/2 n/2的时候那也不满足
  • 剩下的情况就满足(详情看代码)

CODE

#include<bits/stdc++.h>
using namespace std;
#define ll long long
 
const int N = 1e5+10;
 
int t,n;
 
int mp[N][6];
 
 
 
bool check(int l,int r) {//检测l和r这两天能不能满足情况
	int lk,rk,tol;
	lk = rk = tol = 0;
	for(int i = 1;i <= n; ++i) {
		if(mp[i][l]) lk++;
		if(mp[i][r]) rk++;
		if(mp[i][l]||mp[i][r]) tol++;
	}
	int k = n/2;
	if(lk >= k && rk >= k && tol == n) return true;//满足情况返回true
	return false;
}
 
int main()
{
	cin>>t;
	while(t--) {
		cin>>n;
		for(int i = 1;i <= n; ++i) {
			for(int j = 1;j <= 5; ++j) {
				cin>>mp[i][j];
			}
		}
		for(int i = 1;i <= 5; ++i) {
			for(int j = i + 1;j <= 5; ++j) {
				if(check(i,j)){//如果找到了满足的条件,那么就直接goto出去了
					puts("YES");
					goto out;
				}
			}
		}
		puts("NO");
		out:;
	}
	
	return 0;
}

C. Delete Two Elements(map+逆元)

题意

给你n个数,然后有一个

k = ∑ i = 0 n a [ i ] n k =\frac{\sum_{i=0}^n a[i]}{n} k=ni=0na[i]

在这n个元素中选取两个元素删除,然后k值不变的情况的数量有多少种

思路

首先来说删除的这两个数的和肯定和k*2相等,所以我们可以用用map记录下来每次删除的元素的个数,当然k的计算可能会不能整除,所以我们可以用逆元处理一下(因为数据是小于等于1e9的),于是得到了如下代码

CODE

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007

const int N = 2e5+10;

ll t,n;

ll qpow(ll a,ll b,ll c) {
	ll ans = 1;
	while(b) {
		if(b & 1) ans = (ans * a) % c;
		b >>= 1;
		a = (a * a) % c;
	}
	return ans;
}

ll inv(ll x,ll c) {//逆元
	return qpow(x,c-2,c);
}

ll a[N];

map<ll,ll> vis;

int main()
{
	cin>>t;
	while(t--) {
		vis.clear();
		cin>>n;
		ll sum  = 0;
		
		for(int i = 0;i < n; ++i) {
			cin>>a[i];
			sum += a[i];
		}
		ll kk = (((2LL * sum) % mod) * inv(n,mod)) % mod;
		ll ans = 0;
		for(int i = 0;i < n; ++i) {
			ans += vis[(kk-a[i] + mod) % mod];
			vis[a[i]]++;
		}
		cout<<ans<<"\n";
	}
	
	return 0;
}

D. Training Session(组合数)

题意

给你n个问题,每个问题有两个指标:top和difficulties ,我们需要选取三个问题找到满足以下条件的组合情况

  • 三个问题的topics不同
  • 三个问题的difficulties 不同

思路

首先我们可以计算出选取的总情况数: C n 3 = n ∗ ( n − 1 ) ∗ ( n − 2 ) / 6 C_n^3 = n * (n-1) * (n-2)/6 Cn3=n(n1)(n2)/6 ,然后我们从反向思考找到不满足情况,我们以第i个位置得问题作为中心点,则再需要一组其他位置得元素得值即可构成不满足条件得情况,那么我们就可以直接统计这种情况的数量

官方思路:
在这里插入图片描述

CODE

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5+10;

ll t,n;
map<ll,ll> vis1,vis2;
ll a[N],b[N];
vector<ll> V1,V2;

int main()
{
	cin>>t;
	while(t--) {
		vis1.clear();
		vis2.clear();
		cin>>n;
		ll ans = (n * (n-1) / 2LL) * (n-2) / 3LL;
		for(int i = 0;i < n; ++i) {
			scanf("%lld%lld",&a[i],&b[i]);
			vis1[a[i]]++;
			vis2[b[i]]++;
		}
		for(int i = 0;i < n; ++i) {
			ans -= (vis1[a[i]] - 1) * (vis2[b[i]] - 1);//减去不满足条件的情况,以当前这个元素为中心计算
		}
		cout<<ans<<endl;
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MangataTS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值