https://atcoder.jp/contests/arc126
A - Make 10
总共有 ([2,2,3,3],[3,3,4],[2,4,4],[2,2,2,4],[2,2,2,2,2]) 五种拼法,显然如果按照一种拼法拼了就会一直接着按这种拼法,所以我们给这5种拼法一个优先级,按顺序依次执行即可。
#include<bits/stdc++.h>
typedef long long ll;
ll zsy[3],d[5][3]={{2,2,0},{0,2,1},{1,0,2},{3,0,1},{5,0,0}};
int p[5];
int main(){
int T;
scanf("%d",&T);
while(T--){
ll a,b,c,ans=0;
scanf("%lld%lld%lld",&a,&b,&c);
for(int i=0;i<5;i++)p[i]=i;
do{
ll nowans=0;
zsy[0]=a,zsy[1]=b,zsy[2]=c;
for(int i=0;i<5;i++){
int x=p[i];
ll now=1e15;
for(int j=0;j<3;j++)
if(d[x][j]!=0)now=std::min(now,zsy[j]/d[x][j]);
for(int j=0;j<3;j++)
zsy[j]-=now*d[x][j];
nowans+=now;
}
ans=std::max(ans,nowans);
}while(std::next_permutation(p,p+5));
printf("%lld
",ans);
}
return 0;
}
B - Cross-free Matching
注意到最后取法按 a 排序后不存在逆序对,所以我们不妨直接按 a 排序求 lis,要求相同的 a 不能取到,于是相同的 a 的 b 从大到小排即可。
#include<bits/stdc++.h>
typedef long long ll;
struct node{
int a,b;
friend bool operator<(node x,node y){return x.a==y.a?x.b>y.b:x.a<y.a;}
}p[200005];
int n,m;
int c[200005],f[200005],ans;
void add(int x,int v){
while(x<=n){
c[x]=std::max(c[x],v);
x+=x&-x;
}
}
int ask(int x){
int ret=0;
while(x){
ret=std::max(ret,c[x]);
x-=x&-x;
}
return ret;
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++)
p[i].a=read(),p[i].b=read();
std::sort(p+1,p+1+m);
for(int i=1;i<=m;i++)
f[i]=std::max(1,ask(p[i].b-1)+1),add(p[i].b,f[i]),ans=std::max(ans,f[i]);
printf("%d
",ans);
return 0;
}
C - Maximize GCD
对于一个极大 d 满足所有数都是他的倍数那么他就是 gcd。考虑枚举gcd=d计算需要几步,其实就是 ((d-a_imod d)mod d),一开始我以为有单调性于是就写了个二分,但其实这显然没有单调性。但也只是在 (max A) 以内没有,于是我们考虑对小于 (max A) 的数特殊处理,显然可以枚举倍数计算 (a_imod d),于是就 (max A ln max A) 了。
#include<bits/stdc++.h>
typedef long long ll;
int N;
ll zsy[600005],K,ans,s1[600005],s2[600005];
bool check(ll d){
ll ret=0;
for(int i=1;i<=N;i++){
ret+=(d-zsy[i]%d)%d;
if(ret>K)return 0;
}
return 1;
}
int main(){
scanf("%d%lld",&N,&K);
for(int i=1;i<=N;i++)scanf("%lld",zsy+i),s1[zsy[i]]+=zsy[i],s2[zsy[i]]+=1;
std::sort(zsy+1,zsy+1+N);
for(int i=1;i<=600000;i++)s1[i]+=s1[i-1],s2[i]+=s2[i-1];
for(int i=1;i<=300000;i++){
ll now=0;
for(int j=0;j<=300000;j+=i){
// [j+1,j+i-1]
now+=(s2[j+i-1]-s2[j])*(j+i)-(s1[j+i-1]-s1[j]);
if(now>K)break;
}
if(now<=K){
ans=i;
}
}
ll l=zsy[N]+1,r=2e18;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid)){
ans=std::max(ans,mid);
l=mid+1;
}else{
r=mid-1;
}
}
printf("%lld
",ans);
return 0;
}