用贪心的思想,求最好的名次时尽可能让排在后面的人最多,求最差的名次时尽可能让排在前面的人最多
#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;
}
题意:
找到最大的一个集合,使得集合内所有元素 % 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;
}
有 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;
}