比赛链接:http://codeforces.com/contest/1462
D. Add to Neighbour and Remove
大意:给定一个数组a,每次可以任选数组中的一个数加到这个数的相邻的一个位置上的数去,然后再将这个数从数组中删去,问使得数组的所有元素相等的最少操作数。
思路:首先知道的是,最多操作n-1此使得最后剩下一个元素。而不管怎么操作,最后所有数的和是不变的,假设是sum,然后去枚举最后剩余多少个元素,假设是i个,那么这些元素都应该等于sum/i,然后去检查是否可以通过上述操作使得数组等于有i个数等于sum/i的情况。
怎么检查呢?因为我们枚举的是最后剩余多少个元素,所有i是从n-1枚举的,因为只能加到相邻的元素上去,所以我们从左往右扫一遍原数组,看能组成多少个sum/i,如果是i个则输出答案为n-i,否则检查i-1.
Code
#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
#define pirl pair<ll,ll>
#define debug(x) cout << #x << ":" << x << '\n'
const int N = 1e7+7;
const ll mod = 998244353;
const ll ds = 1e18;
const double eps = 1e-8;
ll read(){ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar(); return f*x;}
void print(ll x){ if(x < 0) {putchar('-');x = -x;} if(x/10) print(x/10); putchar(x%10+'0'); }
using namespace std;
int a[3005];
void solve(){
int n,sum = 0;
scanf("%d",&n);
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
sum += a[i];
}
int flag = 0;
for(int i = 0; i < n-1; i++){
if(a[i] != a[i+1]) flag = 1;
}
if(!flag) {
printf("0\n");
return;
}
for(int i = n; i >= 1; i--){
if(sum % i) continue;
int eql = sum / i;
//cout << eql << endl;
int j = 1;
int sum1 = 0,cnt = 0;
while(j <= n && sum1 < eql){
sum1 += a[j];
//if(i == 2) cout << sum1 << endl;
if(sum1 == eql){
sum1 = 0;
cnt++;
}
if(sum1 > eql){
break;
}
j++;
}
if(cnt == i){
printf("%d\n",n-i);
break;
}
}
}
int main(){
int t;
cin >> t;
while(t--)
solve();
//system("pause");
return 0;
}
E2. Close Tuples (hard version)
直接看加强的数据吧。
大意:给定数组a,问有多少个m元组满足m元组中的最大值-最小值<=k.(简单数据中的m和k已经给定,m=3,k=2)
思路:先对数组排序,根据题意可知,那么可以通过a[i]去找到一个元组的右端点j,然后去找在[i,j-1]中找m-1个元组和a[j]组成m元组,答案是
.这是一个可以组成的,因为
,那么a[i+m-1]减去[i,j-1]中的任意一个元素都一定会小于等于k。
Code
#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
#define pirl pair<ll,ll>
#define debug(x) cout << #x << ":" << x << '\n'
const int N = 2e5+7;
const ll mod = 1e9+7;
const ll ds = 1e18;
const double eps = 1e-8;
ll read(){ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar(); return f*x;}
void print(ll x){ if(x < 0) {putchar('-');x = -x;} if(x/10) print(x/10); putchar(x%10+'0'); }
using namespace std;
int a[N];
ll jc[N];
void init(){
jc[0] = 1;
jc[1] = 1;
for(ll i = 2; i <= N; i++){
jc[i] = jc[i-1]*i%mod;
}
}
ll qpow(ll x,ll y){
ll res = 1;
while(y){
if(y&1) res = res*x%mod;
x = x*x%mod;
y >>= 1;
}
return res;
}
void solve(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 0; i < n; i++) scanf("%d",&a[i]);
sort(a,a+n);
ll ans = 0;
for(int i = 0; i < n; i++){
int pos = upper_bound(a,a+n,a[i]+k)-a;
pos--;
int k = pos-i;
if(k < m-1) continue;
ans = (ans+jc[k]*qpow(jc[m-1],mod-2)%mod*qpow(jc[k-(m-1)],mod-2))%mod;
}
printf("%lld\n",ans);
}
int main(){
int t;
init();
cin >> t;
while(t--)
solve();
//system("pause");
return 0;
}
F. The Treasure of The Segments
大意:给出n对[l,r],问最少删掉多少对[l,r],使得剩下的对数中有一对[li,ri],能够覆盖所有的对。
思路:对于每一对去求使得它能覆盖所有对的最少删除数。对于[li,ri],他不能覆盖的是L > ri的和R < li的,这个可以用二分去查找。然后对于所有的最少删除数取min
Code
#include <bits/stdc++.h>
#define ll long long
#define pir pair<int,int>
#define pirl pair<ll,ll>
#define debug(x) cout << #x << ":" << x << '\n'
const int N = 2e5+7;
const ll mod = 1e9+7;
const ll ds = 1e18;
const double eps = 1e-8;
ll read(){ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar(); return f*x;}
void print(ll x){ if(x < 0) {putchar('-');x = -x;} if(x/10) print(x/10); putchar(x%10+'0'); }
using namespace std;
pair<int,int>p[N];
int a[N],b[N];
void solve(){
int n;
scanf("%d",&n);
for(int i = 0; i < n; i++){
scanf("%d%d",&a[i],&b[i]);
p[i] = {a[i],b[i]};
}
sort(a,a+n);
sort(b,b+n);
int ans = n;
for(int i = 0; i < n; i++){
int lnum = 0,rnum = 0;
lnum = lower_bound(b,b+n,p[i].first)-b;
rnum = n-(upper_bound(a,a+n,p[i].second)-a);
ans = min(lnum+rnum,ans);
}
printf("%d\n",ans);
}
int main(){
int t;
cin >> t;
while(t--)
solve();
//system("pause");
return 0;
}