(题目真是大水,居然没有打,气人)
A. Points on the line
题意:n个点,删除一些点,使得剩下点两两距离不超过d,求删除点的最少个数
题解:暴力即可

#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int Max(int a,int b){return a>b?a:b;} inline int read() { int x=0;char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x; } int main() { int n,d,a[105],ans=-1; n=read();d=read(); for(int i=1;i<=n;i++) a[i]=read(); sort(a+1,a+1+n); for(int i=1;i<=n;i++) { for(int j=n;j>=i;j--) { if(a[j]-a[i]<=d) { ans=Max(ans,j-i+1); break; } } } printf("%d",n-ans); return 0; }
B. Our Tanya is Crying Out Loud
题意:一个数初始为n,可以将它减1(花费A代价),或除以k(必须整除,花费B代价),求最小代价
题解:最优策略肯定是先减到能除的最大值,然后除,然后继续减,直到除比减花费更大时,剩下全减,最坏复杂度是logn的,k==1时特判

#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; inline long long read() { long long x=0;char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x; } long long n,k,A,B,ans,now; int main() { n=read();k=read();A=read();B=read(); if(k==1) { printf("%I64d ",(n-1)*A); return 0; } now=n; while(now>1) { ans+=(now%k)*A;now-=now%k; if(now==1) break; if((now-now/k)*A<B) { ans+=(now-1)*A; break; } ans+=B; now/=k; } printf("%I64d",ans); return 0; }
C. Phone Numbers
题意:给你n,k和长度为n的字符串s,求一个由s中字母组成的,长度为k,字典序最小的字符串t,使得t的字典序大于s
题解:把s中所含字母按字典序排个序,然后从后往前枚举t的哪一位大于s

#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; inline int read() { int x=0;char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x; } int n,k,r[2005],cnt,has[2005]; char s[100005]; bool vis[1000]; int main() { n=read();k=read(); scanf("%s",s); for(int i=0;i<n;i++) if(!vis[(int)(s[i])]) r[++cnt]=(int)(s[i]),vis[(int)(s[i])]=1; sort(r+1,r+cnt+1); for(int i=1;i<=cnt;i++) has[r[i]]=i; if(k>n) { printf("%s",s); for(int i=n;i<k;i++) printf("%c",(char)(r[1])); return 0; } for(int i=k-1;i>=0;i--) { if(has[(int)(s[i])]!=cnt) { for(int j=0;j<i;j++) printf("%c",s[j]); printf("%c",(char)(r[has[(int)(s[i])]+1])); for(int j=i+1;j<k;j++) printf("%c",(char)(r[1])); break; } } return 0; }
D. Alena And The Heater
题意:给定数组a,b',和一系列与l,r有关的运算规律,求l,r,使得用a造出的数组b等于b',保证有解
题解:b'中每一位都可以转换成和l,r有关的不等式,随便求求就好了

#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int Min(int a,int b){return a<b?a:b;} int Max(int a,int b){return a>b?a:b;} inline int read() { int 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*10+c-'0',c=getchar(); return x*f; } int n,a[100005],b[100005],ll=-1000000001,lr=1000000000,rl=-1000000000,rr=1000000001,len; int main() { int ma,mi; char B[100005]; n=read();for(int i=1;i<=n;i++) a[i]=read(); scanf("%s",B); len=strlen(B); for(int i=0;i<len;i++) b[i+1]=B[i]-'0'; for(int i=5,j;i<=n;i++) { ma=-1000000005;mi=1000000005; for(int j=i;j>=i-4;j--) mi=Min(a[j],mi),ma=Max(a[j],ma); if(b[i]==b[i-1]) { for(j=i-2;j>=i-4;j--) if(b[j+1]!=b[j]) break; if(j<i-4) { if(b[i]) rl=Max(rr,ma); else lr=Min(ll,mi); } } else { if(b[i]) ll=Max(ll,ma); else rr=Min(rr,mi); } } printf("%d %d",ll+1,rr-1); return 0; }
E. Cashback
题意:给定一段序列,将他们分为诺干段,每一段的价值为这段数字总和减去前(它的长度/c)小的值
题解:DP,dp[i]表示断点为i,一定是分成长度为c比较赚,转移:dp[i]=Min(dp[i-1]+a[i],dp[i-c]+sum[i]-sum[i-c]-(i-c到c的最小值))最小值单调队列(或rmq)维护即可

#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; long long Min(long long a,long long b){return a<b?a:b;} inline long long read() { long long x=0;char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x; } long long n,c,a[100005],dp[100005],que[100005],cnt,tail=1,sum[100005]; void xiu(long long x,long long now) { que[++cnt]=x; while(cnt>tail&&a[que[cnt]]<=a[que[cnt-1]]) que[--cnt]=que[cnt+1]; while(now>que[tail]&&tail<=cnt) tail++; } int main() { n=read();c=read(); for(long long i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i]; for(long long i=1;i<c&&i<=n;i++) dp[i]=dp[i-1]+a[i],xiu(i,0); for(long long i=c;i<=n;i++) xiu(i,i-c+1),dp[i]=Min(dp[i-1]+a[i],dp[i-c]+sum[i]-sum[i-c]-a[que[tail]]); printf("%I64d ",dp[n]); return 0; }
F. Machine Learning
题意:给你一个数组,和q次操作,单点修改或者查询一段区间的mex值(设区间内i的出现次数为ci,mex值为集合c与正整数集的补集的最小值)
题解:带修莫队+简单暴力,稍微离散一下,因为ci最多有根号n种,复杂度O(n^(5/3)+n根号n)(代码巨丑无比)

#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; inline int read() { int x=0;char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return x; } struct xun{ int l,r,t,id; }q[100005]; int n,m,c[100005],be[100005],cnt1,cnt2=1,xiu[3][100005],sum[200005],ans[100005],ansum[100005],nnum[200005],anum[200005],cnu; bool cmp(xun a,xun b){return be[a.l]==be[b.l]?(be[a.r]==be[b.r]?a.t<b.t:a.r<b.r):a.l<b.l;} void rev(int x,int add) { ansum[sum[x]]--; sum[x]+=add; ansum[sum[x]]++; } void rev1(int x,int l,int r) { int a=c[xiu[0][x]],b=xiu[1][x];xiu[2][x]=a; c[xiu[0][x]]=b; if(xiu[0][x]>=l&&xiu[0][x]<=r) { ansum[sum[a]]--;ansum[--sum[a]]++; ansum[sum[b]]--;ansum[++sum[b]]++; } } void rev2(int x,int l,int r) { int a=c[xiu[0][x]],b=xiu[2][x]; c[xiu[0][x]]=b; if(xiu[0][x]>=l&&xiu[0][x]<=r) { ansum[sum[a]]--;ansum[--sum[a]]++; ansum[sum[b]]--;ansum[++sum[b]]++; } } bool check(int x,int s) { if(nnum[x]<c[s]) return 1; else return 0; } bool check2(int x,int s) { if(nnum[x]<xiu[1][s]) return 1; else return 0; } int main() { int l,r,now=0,mid; n=read();m=read(); int ttt=pow(n,2.0/3.0); for(int i=1;i<=n;i++) c[i]=read(),be[i]=i/ttt,nnum[++cnu]=c[i]; for(int i=1,s;i<=m;i++) { s=read(); if(s==1) q[++cnt1].l=read(),q[cnt1].r=read(),q[cnt1].t=cnt2,q[cnt1].id=cnt1; else xiu[0][++cnt2]=read(),xiu[1][cnt2]=read(),nnum[++cnu]=xiu[1][cnt2]; } sort(nnum+1,nnum+cnu+1); for(int i=1,mmax=-1;i<=cnu;i++) { if(nnum[i]>mmax) mmax=nnum[i],now++; anum[i]=now; } for(int i=1,mid;i<=cnu;i++) { l=1,r=cnu; if(i<=n) { while(l<r) { mid=l+r>>1; if(check(mid,i)) l=mid+1; else r=mid; } c[i]=anum[l]; } else { while(l<r) { mid=l+r>>1; if(check2(mid,i-n+1)) l=mid+1; else r=mid; } xiu[1][i-n+1]=anum[l]; } } sort(q+1,q+1+cnt1,cmp); l=1;r=0;now=1; for(int i=1;i<=cnt1;i++) { while(r<q[i].r) rev(c[++r],1); while(l>q[i].l) rev(c[--l],1); while(l<q[i].l) rev(c[l++],-1); while(r>q[i].r) rev(c[r--],-1); while(now<q[i].t) rev1(++now,l,r);while(now>q[i].t) rev2(now--,l,r); for(int j=1;j<=200000;j++){if(!ansum[j]){ans[q[i].id]=j;break;}} } for(int i=1;i<=cnt1;i++) printf("%d ",ans[i]); return 0; }