A. Satisfying Constraints
- 贪心
- k ≥ x k \geq x k≥x,只需大于最大的 x x x即可满足要求
- k ≤ x k \leq x k≤x,只需小于最小的 x x x即可满足要求
- k ≠ x k \neq x k=x,将所有的 x x x用set记录下来,在范围内排除 x x x即可
AC代码
#include<iostream>
#include<set>
using namespace std;
long long read(){
long long x=0,w=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')w=-1;
c=getchar();
}
while(isdigit(c)){
x=(x<<1)+(x<<3)+(c&15);
c=getchar();
}
return x*w;
}
int main(){
int t=read();
while(t--){
int n=read();
int one=0,two=0x3f3f3f3f;
set<int>three;
while(n--){
int a=read(),x=read();
if(a==1)one=max(x,one);
else if(a==2)two=min(x,two);
else three.insert(x);
}
int ans=two-one+1;
for(int i:three)if(one<=i&&i<=two)ans--;
cout<<max(0,ans)<<endl;
}
}
B. Summation Game
- 博弈
由于所有数均为正整数,所以Alice和Bob的操作必定使得总和变小。首先对数组从大到小排序,设前 x x x个数的前缀和为 s u m x sum_x sumx。
- Bob需要结果尽可能小,则Bob选取前 x x x个最大的数将其变为负数,则总和减小 2 s u m x 2sum_x 2sumx。
- Alice需要结果尽可能大,但Alice删除
a
i
a_i
ai将导致总和减小
a
i
a_i
ai。
易知:若Alice先删除了不会被Bob操作的数将会导致总和更小,所以Alice删除的数必定是Bob操作的数。需注意并不是前 x x x个数,因为Bob的操作会因为Alice的操作而发生改变。 - Alice若删除了Bob本应操作的数,Bob的操作则会顺延到第 x x x个数之后,则Alice需要保证删除的第 i i i个数 a i > 2 a x + i a_i>2a_{x+i} ai>2ax+i,即 s u m n − a i − 2 a x + 1 > s u m n − 2 a i sum_n-a_i-2a_{x+1}>sum_n-2a_i sumn−ai−2ax+1>sumn−2ai ,Alice删除 a i a_i ai及Bob将 a x + i a_{x+i} ax+i取负的值应小于Bob将 a i a_i ai取负的值。
- 由于数组已预先排好序,则 a j ≥ a j + 1 a_j\geq a_{j+1} aj≥aj+1,若 a j + 1 > 2 a x + i a_{j+1}>2a_{x+i} aj+1>2ax+i,则有 a j > 2 a x + i a_{j}>2a_{x+i} aj>2ax+i,所以只需从左到右遍历Alice可能操作的前 k k k个数即可得出答案。
AC代码
#include<bits/stdc++.h>
using namespace std;
long long read(){
long long x=0,w=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')w=-1;
c=getchar();
}
while(isdigit(c)){
x=(x<<1)+(x<<3)+(c&15);
c=getchar();
}
return x*w;
}
int main(){
int t=read();
while(t--){
int n=read(),k=read(),x=read();
int a[n+1];
long long sum[n+1];
sum[0]=0;
for(int i=1;i<=n;++i)a[i]=read();
sort(a+1,a+n+1,greater<>());
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+a[i];
long long cut=sum[x]<<1;
long long ans=sum[n]-cut;
for(int i=1;i<=k;++i){
cut=(sum[min(n,x+i)]-sum[i])<<1;
ans=max(ans,sum[n]-sum[i]-cut);
}
cout<<ans<<endl;
}
}
C. Partitioning the Array
- 数论
对于任意可能的 k k k,每组数组中相同位置的数取模需相同,即 a i m o d m ≡ a i + k m o d m a_i\mod m\equiv a_{i+k}\mod m aimodm≡ai+kmodm ,可转化为 ∣ a i − a i + k ∣ ≡ 0 m o d m |a_i-a_{i+k}|\equiv0\mod m ∣ai−ai+k∣≡0modm。
由于 m > 1 m>1 m>1,所以对于任意k,需要遍历数组确定 m > 1 m>1 m>1。
特别地,当 m = 0 m=0 m=0时,代表不存在元素 a 1 + k a_{1+k} a1+k,即只有一个数组,故 m m m可以取任何值。
AC代码
#include<bits/stdc++.h>
using namespace std;
long long read(){
long long x=0,w=1;
char c=getchar();
while(!isdigit(c)){
if(c=='-')w=-1;
c=getchar();
}
while(isdigit(c)){
x=(x<<1)+(x<<3)+(c&15);
c=getchar();
}
return x*w;
}
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int t=read();
while(t--){
int n=read();
int a[n];
for(int i=0;i<n;++i)a[i]=read();
int ans=0;
for(int i=1;i<=n;++i){
if(n%i==0){
int g=0;
for(int j=i;j<n;++j){
g=gcd(g,abs(a[j]-a[j-i]));
}
ans+=(g!=1);
}
}
cout<<ans<<endl;
}
}