A
http://codeforces.com/contest/1406/problem/A
桶排个序,记录一下个数,然后从小到大扫两遍,每次直到个数为零的那个数,将他们加起来即可。
#include <bits/stdc++.h>
using namespace std;
int T,ans,n,i,GG,f[200],a[200];
int main(){
cin >>T;
while (T--){
ans=0;
cin >>n;
memset(f,0,sizeof(f));
for (i=1; i<=n; i++){
cin >>a[i];
f[a[i]]++;
}
for (i=0,GG=0; !GG; i++){
if (f[i]){f[i]--; continue;}
if (!f[i]) ans+=i,GG=1;
}
for (i=0,GG=0; !GG; i++){
if (f[i]){f[i]--; continue;}
if (!f[i]) ans+=i,GG=1;
}
cout <<ans <<"\n";
}
}
B
http://codeforces.com/contest/1406/problem/B
选的数比较少,我先把读入的数组按正负分成两组,分别算出他们选 1,2,…,5 个数乘起来的最值,然后组合判断一下,选最优的就行了。注意一下可能出现0.
#include <bits/stdc++.h>
using namespace std;
int T,n,cnt1,cnt2,cnt3,tmp;
long long a1[100005],a2[100005],b1[100005],b2[100005],b3[100005],ans;
bool cmp(int x,int y){return x>y;}
int main(){
cin >>T;
while (T--){
memset(a1,0,sizeof(a1));
memset(a2,0,sizeof(a2));
cin >>n;
cnt1=cnt2=cnt3=0;
for (int i=1,tmp; i<=n; i++){
cin >>tmp;
if (tmp<0) a1[++cnt1]=tmp;
if (tmp>0) a2[++cnt2]=tmp;
if (tmp==0) cnt3++;
}
if (cnt3>n-5){
cout <<"0\n";
continue;
}
sort(a1+1,a1+cnt1+1,cmp);
sort(a2+1,a2+cnt2+1,cmp);
b1[0]=b2[0]=b3[0]=1;
for (int i=1; i<=5; i++) if (i<=cnt1) b1[i]=b1[i-1]*a1[i];
for (int i=cnt1,k=1; k<=5 && i; i--,k++) b3[k]=b3[k-1]*a1[i];
b2[0]=1;
for (int i=1; i<=5; i++) if (i<=cnt2) b2[i]=b2[i-1]*a2[i];
ans=-300000000000000000ll;
if (cnt3) ans=0;
for (int i=0; i<=5; i++) if (cnt1>=i && cnt2>=5-i){
ans=max(ans,b1[i]*b2[5-i]);
ans=max(ans,b3[i]*b2[5-i]);
}
cout <<ans <<"\n";
}
}
C
http://codeforces.com/contest/1406/problem/C
D
http://codeforces.com/contest/1406/problem/D
答案满足二分单调条件,先二分答案。
模拟一下过程,会发现b,c数组最优情况和 a 数组的相邻差值有关,比如从左往右排,那么c[1]选二分的m肯定最优,之后能算出b[1],再根据 a[2] 与 a[1] 的大小关系选择 c[2]继承c[1] 还是 b[2]继承b[1],(可以想像,相邻两位中bc至少其中一项相同,是更优的),一直到最右边,判断一下 b[n] 是否大于 m 即可。
但题目还有区间修改的维护要求,我开始想的是用树状数组维护,但是会超时。
后来再想想,发现其实可以把差值按正负分开求和,分别加到b[1]和c[1]上,得到的结果就是b[n]和c[n]了,这样check()的时候就是 O1 的了,于是问题解决。
看图可能更清除一点。(数据是我下面程序中末端注释中那一组)
#include <cstdio>
#define M ((l+r)>>1)
#define lowbit(x) (x&(-x))
long long n,L,R,X,q,sb,sc,ll,rr,a[100005];
long long ans;
int check(long long x){
if ((ll-x+sb)>x) return 0;
return 1;
}
void ef(long long l,long long r){
if (l==r){
ans=l;
return;
}
if (check(M)){
ef(l,M);
return;
}
ef(M+1,r);
}
int main(){
scanf("%lld",&n);
for (int i=1; i<=n; i++) scanf("%lld",&a[i]);
for (int i=1; i<n; i++){
if (a[i+1]>a[i]) sb+=a[i+1]-a[i];
else sc+=a[i+1]-a[i];
}
ll=a[1],rr=a[n];
for (int i=1; i<n; i++) a[i]=a[i+1]-a[i];
//for (int i=1; i<=n; i++) S.Add(i,i,a[i]);
ef(-10000000000000000ll,10000000000000000ll);
printf("%lld\n",ans);
scanf("%lld",&q);
while (q--){
scanf("%lld%lld%lld",&L,&R,&X);
if (L==1) ll+=X;
if ((L-1)>0) (a[L-1]>0) ? sb-=a[L-1] : sc-=a[L-1];
if (R<n) (a[R]>0) ? sb-=a[R] : sc-=a[R];
if (L-1>0) a[L-1]+=X;
if (R<n) a[R]-=X;
if ((L-1)>0) (a[L-1]>0) ? sb+=a[L-1] : sc+=a[L-1];
if (R<n) (a[R]>0) ? sb+=a[R] : sc+=a[R];
ef(-10000000000000000ll,10000000000000000ll);
printf("%lld\n",ans);
}
}
/*
4
-3 6 -2 -8
3
1 3 -4
3 3 5
3 3 -4
*/
E
http://codeforces.com/contest/1406/problem/E
发现这样一个东西:
一组询问
B p
A p
就可以知道x是不是p的倍数。
那么有两种思路:
一种是直接从2往后询问,边问边把后面不符合的删掉,时间复杂度好像挺高
另一种是把 n 里面的质数先问了,再将得出为 x 因数的质数拿出来乘方询问,得到它们的幂,感觉一下似乎复杂度是够的。(不过程序还没写出来 LOL