Educational Codeforces Round 117 (Rated for Div. 2)

本文探讨了几个算法问题,包括距离计算、特殊排列的处理、聊天禁令检查、X-Magic Pair概念、消息操作、二分查找以及概率公式在卡片抽取问题中的应用。通过实例代码展示了如何使用硬模拟、二分搜索和概率模型来解决这些问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. Distance
B. Special Permutation
C. Chat Ban
D.X-Magic Pair
E. Messages
F:没看F,好难的样子
G. Max Sum Array

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <map>
#define mid (l+r>>1)
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 1e5, M = 5e2;

int main() 
{
	int t;
	scanf("%d", &t);
	while(t --)
	{
		int a, b;
		scanf("%d%d", &a, &b);
		if(abs(a)+abs(b)&1)puts("-1 -1");
		else{
			int x = abs(a)>>1, y = (abs(a)+abs(b)>>1)-x;
			if(a<0)x=-x;
			if(b<0)y=-y;
			cout<<x<<' '<<y<<endl;
		}
	}
	return 0;
}

硬模拟

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <map>
#define mid (l+r>>1)
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 1e5, M = 5e2;

int main() 
{
	int t;
	scanf("%d", &t);
	while(t --)
	{
		int n, a, b, l = 1, r = 2, pos[N]={0}, nl = 0, nr = 0;
		bool f = 0;
		scanf("%d%d%d", &n, &a, &b);
		for(int i = n;i > b;i --)pos[i] = l, nl++;
		if(!pos[a])pos[a] = l, nl++;
			
		for(int i = 1;i < a;i ++)f |= pos[i] == l, pos[i] = r, nr++;
		if(!pos[b]) f |= pos[b] == l, pos[b] = r, nr++;
		
		for(int i = a+1;i < b;i ++)
			if(!pos[i])
			{
				if(nl < n/2)pos[i] = l, nl++;
				else pos[i] = r;
			}
			
		if(f || nl!=n/2)puts("-1");
		else{
			for(int i = 1;i <= n;i ++)if(pos[i] == l)cout<<i<<' ';
			for(int i = 1;i <= n;i ++)if(pos[i] == r)cout<<i<<' ';
			puts("");
		}
	}
	return 0;
}

二分直接算

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <map>
#define mid (l+r>>1)
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 1e5, M = 5e2;

LL k, x;

bool ch(LL l)
{
	LL sum = 0;
	if(l>k) sum = (1+k)*k/2 + (k+2*k-l-1)*(l-k)/2;
	else sum = (1+l)*l/2;
	return sum>=x;
}
int main() 
{
	int t;
	scanf("%d", &t);
	while(t --)
	{
		scanf("%lld%lld", &k, &x);
		LL l = 1, r = 2*k-1;
		while(l < r)
		{
			if(ch(mid)) r=mid;
			else l=mid+1;
		}
		cout<<l<<endl;
	}
	return 0;
}

队友写的,没搞懂

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <map>
#define mid (l+r>>1)
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 1e5, M = 5e2;

int main() 
{
	int t;
	scanf("%d", &t);
	while(t --)
	{
		LL a, b, x;
		bool f = 0;
		scanf("%lld%lld%lld", &a, &b, &x);
		if(x<=max(a, b)){
			while(a>=x||b>=x&&a&&b){
				if(a<b)swap(a, b);
				if(a==x||b==x||(a-x)%b==0){
					f = 1;break;
				}
				a %= b;
			}
		}
		puts(f?"YES":"NO");
	}
	return 0;
}

概率公式计算,假设有n张牌,其中里面有他要的,它可以抽k张牌,如果k>n那么这个人的期望就是n/n,否则是1 - ( n − 1 k ) \tbinom{n-1}{k} (kn1)/ ( n k ) \tbinom{n}{k} (kn) = k / n。
 然后可以枚举小于20的n枚举的时候k大于n的贡献要变成1。
 对于大于20的n来说答案就可以按照期望贡献对数字排序,再进行递推枚举计算。

具体看代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <map>
#define mid (l+r>>1)
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 2e5+10, M = 5e2;

int a[N][21]; 
PII b[N];
vector<int>ans;

int main() 
{
	int n;
	scanf("%d", &n);
	for(int i = 1;i <= n;i ++){
		int x, y;
		scanf("%d%d", &x, &y);
		a[x][y]++;  //有个 数字为x,k等于y的人 
	}
	LL ma = 0, mn = 1;   // ma 是最大值, mn是最大值个数其实在ans-vector里有体现; 
	for(int i = 1;i <= 20;i ++){      // 枚举n  
		for(int j = 1;j <= 2e5;j ++){ // 遍历每个树 
			int sum = 0;  // 当n等于i时数字i对于期望的贡献 
			for(int k = 1;k <= i;k ++)sum += a[j][k]*k;  // k < n时 k = k, k ≥n时 k = n;  
			for(int k = i+1;k <= 20;k ++)sum += a[j][k]*i;
			b[j] = {-sum, j};   // 第一关键字取反按照从小往大排序的话第一个取反就是最大值; 
		}
		sort(b+1, b+(int)2e5+1);  
		LL sum = 0;
		for(int x = 1;x <= i;x ++)
			sum += -b[x].first;
		if(sum*mn>ma*i){   // 分式化乘法 
			ans.clear();
			for(int x = 1;x <= i;x ++)
				ans.push_back(b[x].second);
			ma = sum; 
			mn = i;
		}	
	}
	LL h = 0;
	for(int i = 1;i <= 20&&i <= n;i ++)
		h += -b[i].first;  // 这时候是先求出前二十个的和; 
	for(int i = 21;i <= n;i ++) // 枚举21 - n 的个数取值; 
	{
		h += -b[i].first;
		if(h*mn>ma*i)ma = h, mn = i;
	}
	if(mn > 20)
		for(int i = 1;i <= mn;i ++)
			ans.push_back(b[i].second);
	cout<<ans.size()<<endl;
	
	for(auto x: ans)cout<<x<<' ';cout<<endl;
	return 0;
}

  没人补G吗,假设有n个相等数字且位置为P1 P2 P3 …Pn,那么你计算之后就可以得到 ∑ i = 1 n \sum_{i=1}^n i=1n ( 2 ∗ \ast i - n -1) ∗ \ast Pi

  那么再对于每个n都确定前面的 ( 2 ∗ \ast i - n -1),那么这个东西就由 Pi 确定,然后可以看出( 2 ∗ \ast i - n -1)要么都是奇数要么都是偶数那么再把不连续的变成连续的(这步在代码里面有注释), 再挨个计算,数量就是( 2 ∗ \ast i - n -1)相等的数量的阶乘的乘积

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <set>
#define mid (l+r>>1)
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N = 2e6+10, mod = 1e9 + 7;
void mull(int &a, LL b){a = a*b%mod;return ;}
void add(int &a, LL b){a = (a+b)%mod;return ;}

LL a[N], b[N], in[N];
// a :-2 0 2 4 6 -> -1 0 1 2 3       n 是奇数 
// b :-3 -1 1 3  -> -2  0 2 4 < a    n 是偶数 
LL se(LL a, int b){a%=mod;return b*(a+a+b-1)%mod*500000004%mod;}

int main() 
{
	int n;
	scanf("%d", &n);in[0] = 1;
	for(int i = 1;i <= n;i ++)
	{
		int x;
		scanf("%d", &x);
		LL *t = a, f = 0;
		if(x%2 == 0)t = b, f = 1;

		t[(1-x+f)/2+(int)1e6]++;
		t[(x-1+f)/2+(int)1e6+1]--;
		in[i] = i*in[i-1]%mod;
	}
	int ans = 0, sum = 1;
	LL head = 1;
	for(int i = 0;i <= 2e6;i ++)
	{
		a[i] += a[i-1]; b[i] += b[i-1];
		add(ans, ((i-(int)1e6)*2-1)*se(head, b[i])%mod);
		head += b[i];
		add(ans, ((i-(int)1e6)*2)*se(head,   a[i])%mod);
		head += a[i];
		mull(sum, in[b[i]]*in[a[i]]%mod);
	}
	add(ans, mod);
	cout<<ans<<' '<<sum<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

李昌荣。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值