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\n",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\n",ans);
return 0;
}
C - Maximize GCD
對於一個極大 d 滿足所有數都是他的倍數那么他就是 gcd。考慮枚舉gcd=d計算需要幾步,其實就是 \((d-a_i\bmod d)\bmod d\),一開始我以為有單調性於是就寫了個二分,但其實這顯然沒有單調性。但也只是在 \(\max A\) 以內沒有,於是我們考慮對小於 \(\max A\) 的數特殊處理,顯然可以枚舉倍數計算 \(a_i\bmod 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\n",ans);
return 0;
}