2021“MINIEYE杯”(c,h,j)

比赛链接
C - Dota2 Pro Circuit

用贪心的思想,求最好的名次时尽可能让排在后面的人最多,求最差的名次时尽可能让排在前面的人最多

#include<bits/stdc++.h>
#define fo(a,b,c) for(int a=b;a<c;a++)
using namespace std;
typedef long long ll;
struct A{
    int point,i;
};
bool cmp(A a,A b){return a.point<b.point;}
int main()
{
    int t,n;
    cin>>t;
    while(t--){
        cin>>n;
        A a[n];
        int b[n],maxx[n],minn[n];
        fo(i,0,n)cin>>a[i].point,a[i].i=i;
        sort(a,a+n,cmp);
        fo(i,0,n)cin>>b[i];
        if(n==1){cout<<1<<" "<<1<<endl;continue;}
        fo(i,0,n){
            int ma=a[i].point+b[0],mi=a[i].point+b[n-1];
            int p=0,x=1;
            for(int j=0;j<n;j++){
                if(j==i)continue;
                if(a[j].point+b[p]>mi){
                    x++; p++;
                }
            }minn[a[i].i]=x;
            p=n-1,x=1;
            for(int j=n-1;j>=0;j--){
                if(j==i)  continue;
                if(a[j].point+b[p]>ma)
                    x++;
                else p--;
            }maxx[a[i].i]=x;
        }
        fo(i,0,n)cout<<maxx[i]<<" "<<minn[i]<<endl;
    }
	return 0;
}

H - Integers Have Friends 2.0

题意:
找到最大的一个集合,使得集合内所有元素 % m(>=2)相等,问最大的集合大小
取m == 2的情况下,答案为 1/2
选择两个位置,这两个数的位置均在答案中的可能性至少为1/4,反之可能性为3/4,假如重复取30次,则为0.00017可以看作为0,所以方法是可靠的。选定了两个位置p1,p2之后,m可以取diff = abs(a[p1]-a[p2])的质因子,枚举diff的因子来当m进行操作,过程中一直取max即可

#include<bits/stdc++.h>
#define fo(a,b,c) for(int a=b;a<c;a++)
using namespace std;
typedef long long ll;
const int N = 3e6+10;
ll n,a[N];
ll cal(ll x,ll y) {
	ll cnt = 0;
	for(int i=1; i<=n; i++)
		if(a[i] % x == y) cnt ++;
	return cnt;
}
int main()
{
    srand(time(NULL));
    int t;cin>>t;
    while (t--) {
        cin>>n;
        for (int i = 1; i <= n; i++)cin>>a[i];
        ll ans = 1;
        for (int i = 1; i <= 30; i++) {
            int p1=1,p2=1;
            while (p1 == p2) {
                p1 = rand() % n + 1;
                p2 = rand() % n + 1;
            }
            ll diff = abs(a[p1] - a[p2]);
            for (ll i = 2; 1ll * i * i <= diff; i++)
                if (diff % i == 0) {
                    while (diff % i == 0)
                        diff /= i;
                    ans = max(ans, cal(i, a[p1] % i));
                }
            if (diff > 1) ans = max(ans, cal(diff, a[p1] % diff));
        }
        cout<<ans<<endl;
    }
    return 0;
}

J-Unfair contest

有 n − 1 个评委分别为 A ,B 两个人打分,记为 a1 , a2 , ⋯   , a~n − 1~与 b1 , b2 , ⋯   , b~n − 1~,所有评委打分范围不得超出[1,h]。由于第 n 名评委和 A关系很好,所以他希望 A 能赢。记分规则为删除 s 个最高分,删除 t 个最低分,其余的取平均分。如果无论评委如何操作 A 都的最终得分都无法严格大于 B的最终得分,输出 “IMPOSSIBLE”,否则,在保证 A 能赢 B的前提下,我们需要最小化差值 an − bn ,并输出这个差值。(“为了不让作弊看起来那么明显”)

解题思路
参照
前 n表示已知评分的评委数,当前评委编号为n+1。
把 { a i } 和 { b i }分别从小到大排序。由于要删除 s个最高分和t 个最低分,因此无论最后一名评委如何给分,两个数列的前t−1 个元素和后s−1 个元素一定是没有用的,而 t + 1 ∼ n − s内一定不会被删去。 at与 an−s+1是否被删除取决于 an+1(bt与 bn−s+1同理)。
当 an+1< at 时,at不被删除,对答案造成贡献。当 an+1∈ [ at , an−s+1 ] 时,an+1对答案造成贡献。当 at > an−s+1 时,an−s+1对答案造成贡献。为了使an+1 − bn+1 最小,当an+1>an−s+1 的情况时,直接使an+1=an−s+1。当 an+1< at,直接使 an+1=1 。
因此an+1 ∈ 1 ∪ [ at , an−s+1 ] ,bn+1 ∈ [ bt , bn−s+1 ]∪h 。
对于 s = 0以及 t = 0 的情况,分别添加两个元素 1、h,再令 s++, t++即可。

SumA+ac >SumB+bc ⇔SumA+ac >SumB+bc +1
即ac −bc ≥ SumB−SumA+1
ac是{at ,an+1, an−s+1}的中位数,bc是{bt ,bn+1, bn−s+1}的中位数
SumA、SumB为有效部分分数和

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 100000 + 10;
const long long inf = 0x7f7f7f7f7f7f7f7fLL;
int A[maxn], B[maxn]; 
int main() {
	int T; scanf("%d", &T);
	while(T --) {
		int n, s, t, h; scanf("%d%d%d%d", &n, &s, &t, &h);
		for(int i = 1; i <= n-1; i ++) scanf("%d", &A[i]);
		for(int i = 1; i <= n-1; i ++) scanf("%d", &B[i]);
		A[n] = 1; A[n+1] = h;
		B[n] = 1; B[n+1] = h;
		n ++; s ++; t ++; 
		sort(A + 1, A + n + 1);
		sort(B + 1, B + n + 1);
		
		long long SumA = 0, SumB = 0; 
		for(int i = t + 1; i <= n - s; i ++) {
			SumA += A[i];
			SumB += B[i];
		}
		long long ans = inf;
		long long Btmp = A[t] + SumA - SumB - 1;
		
		if(Btmp >= B[t]) {
			long long Bt = min(Btmp, (long long)B[n-s+1]);
			ans = min(ans, 1 - Bt);
		}
		long long Atmp = B[n-s+1] + SumB - SumA + 1; /// 此时有 A_{n+1} >= Atmp 
		if(Atmp <= A[n-s+1]) {
			long long At = max((long long)A[t], Atmp);
			ans = min(ans, At - h);
		}
		if(A[t] - B[n-s+1] >= SumB - SumA + 1) {
			ans = min(ans, 1ll - h);
		}
		if(A[n-s+1] - B[t] >= SumB - SumA + 1) {
			ans = min(ans, max(SumB - SumA + 1, (long long)A[t] - B[n-s+1]));
		}
		
		ans == inf ? puts("IMPOSSIBLE") : printf("%lld\n", ans); 
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值