A:给数组a,sort后求最长区间[l,r]使区间内max-min<=d,输出n-最长区间长度。
题解:暴力。。。
#include<cstdio> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<map> #include<set> #include<queue> #include<vector> #define mp make_pair using namespace std; typedef long long LL; typedef pair<int,int> pa; const int N=1001; //struct E{int to,nxt;}e[N<<1]; int n,a[N]; int Write[20],WRI; void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);} int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;} void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));} //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;} //void Add(LL x,LL y){add(x,y); add(y,x);} int main() { //judge(); n=read(); int d=read(); for (int i=1;i<=n;i++) a[i]=read(); int ans=1000000; sort(a+1,a+1+n); for (int i=1,j=1;i<=n;i++) { while (j<n&&a[j+1]-a[i]<=d) j++; ans=min(ans,n-(j-i+1)); } printf("%d",ans); return 0; }
B:有一个数x=n,可以用A的金币使x--,或在x%k==0时用B的金币使x/=k,求将它变为1的最小代价。
题解:贪心,先使x%=k,然后比较用A和B那个优,注意一些细节,没开long long爆了4发,┭┮﹏┭┮
#include<cstdio> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<map> #include<set> #include<queue> #include<vector> #define mp make_pair using namespace std; typedef long long LL; typedef pair<int,int> pa; //struct E{int to,nxt;}e[N<<1]; LL n,A,B,k,x; int Write[20],WRI; void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);} LL read(){LL d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;} void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));} //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;} //void Add(LL x,LL y){add(x,y); add(y,x);} int main() { //judge(); n=read(); k=read(); A=read(); B=read(); if (k==1) { printf("%lld",(n-1)*A); return 0; } x=n; LL ans=0; while (x!=1) { if (x<k) {ans+=(x-1)*A; break;} ans+=x%k*A; x-=x%k; if ((x-x/k)*A>B) ans+=B; else ans+=(x-x/k)*A; x/=k; } printf("%lld",ans); return 0; }
C:给一个字符串s,求字典序最小的字符串a,使a的长度为k,且a的字典序大于s,且a的字符集是s的子集
题解:k>n时,在原串后加上k-n个s中最小字母即可,k<=n时,用类似进制加1的方法,使最后一位变为比它大的最小字符,如果它已经是最大的,就“进位”上去。
#include<cstdio> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<map> #include<set> #include<queue> #include<vector> #define mp make_pair using namespace std; typedef long long LL; typedef pair<int,int> pa; const int N=100010; //struct E{int to,nxt;}e[N<<1]; int n,k,t,b[26]; char s[N],f[26]; int Write[20],WRI; void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);} int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;} void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));} //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;} //void Add(LL x,LL y){add(x,y); add(y,x);} int main() { //judge(); n=read(); k=read(); scanf("%s",s+1); for (int i=1;i<=n;i++) b[s[i]-'a']=1; for (int i=0;i<26;i++) if (b[i]) f[++t]=(char)(i+'a'); if (n==k) { int x=n; while (s[x]==f[t]) s[x]=f[1],x--; for (int i=1;i<=t;i++) if (f[i]==s[x]) {s[x]=f[i+1]; break; } for (int i=1;i<=n;i++) printf("%c",s[i]); } else if (n<k) { for (int i=1;i<=n;i++) printf("%c",s[i]); for (int i=1;i<=k-n;i++) printf("%c",f[1]); } else { int x=k; while (s[x]==f[t]) s[x]=f[1],x--; for (int i=1;i<=t;i++) if (f[i]==s[x]) {s[x]=f[i+1]; break; } for (int i=1;i<=k;i++) printf("%c",s[i]); } return 0; }
D:有两个数组a,b,b的生成规则如下:
b1 = b2 = b3 = b4 = 0.
For all 5 ≤ i ≤ n:
- bi = 0 if ai, ai - 1, ai - 2, ai - 3, ai - 4 > r and bi - 1 = bi - 2 = bi - 3 = bi - 4 = 1
- bi = 1 if ai, ai - 1, ai - 2, ai - 3, ai - 4 < l and bi - 1 = bi - 2 = bi - 3 = bi - 4 = 0
- bi = bi - 1 otherwise
求一组满足条件的l,r
题解:直接暴力求解即可。。。
#include<cstdio> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<map> #include<set> #include<queue> #include<vector> #define mp make_pair using namespace std; typedef long long LL; typedef pair<int,int> pa; const int N=100010; //struct E{int to,nxt;}e[N<<1]; int n,b[N],l,r; char a[N]; int Write[20],WRI; void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);} int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;} void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));} //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;} //void Add(LL x,LL y){add(x,y); add(y,x);} int main() { //judge(); n=read(); l=-1000000000; r=1000000000; for (int i=1;i<=n;i++) b[i]=read(); scanf("%s",a+1); for (int i=5;i<=n;i++) if (a[i]!=a[i-1]&&a[i-1]==a[i-2]&&a[i-2]==a[i-3]&&a[i-3]==a[i-4]) if (a[i]=='1') { for (int j=i-4;j<=i;j++) l=max(l,b[j]+1); } else { for (int j=i-4;j<=i;j++) r=min(r,b[j]-1); } printf("%d %d",l,r); return 0; }
E:将数组a划分成若干段,使每段的f值之和最小,其中f值是区间内元素和减去前k/c(下取整)小的数。
题解:考虑去掉2个数,也就是2c<=段长<3c时,将它拆成两段肯定不会变劣,这应该比较显然吧,然后取c肯定不会劣于c+1,那么我们在DP时只要从i-c和i-1转移过来即可,同时要维护[i-c+1,i]的最小值,我是用单调队列的。
#include<cstdio> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<map> #include<set> #include<queue> #include<vector> #define mp make_pair using namespace std; typedef long long LL; typedef pair<int,int> pa; const int N=100010; //struct E{int to,nxt;}e[N<<1]; #define int LL int n,a[N],c,q[N],h,t; LL s[N],f[N]; int Write[20],WRI; void judge(){freopen(".in","r",stdin);freopen(".out","w",stdout);} int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;} void write(int x){if (!x){putchar('0'); return;}if (x<0) putchar('-'),x=-x;for (WRI=1;x;x/=10,WRI++) Write[WRI]=x%10;for (int i=WRI-1;i;i--) putchar((char)(Write[i]+48));} //void add(LL x,LL y){e[++cnt]=(E){y,head[x]}; head[x]=cnt;} //void Add(LL x,LL y){add(x,y); add(y,x);} signed main() { //judge(); n=read(); c=read(); for (int i=1;i<=n;i++) a[i]=read(),s[i]=s[i-1]+a[i]; h=1; for (int i=1;i<=n;i++) { f[i]=f[i-1]+a[i]; while (h<=t&&q[h]<i-c+1) h++; while (h<=t&&a[q[t]]>a[i]) t--; q[++t]=i; //for (int j=h;j<=t;j++) printf("%d ",q[j]); puts(""); if (i>=c) f[i]=min(f[i],f[i-c]+s[i]-s[i-c]-a[q[h]]); } printf("%lld",f[n]); return 0; }
F:给数组a,有两种操作,1 l r查询[l,r]中每个数出现次数的mex,注意是出现次数,mex是最小未出现的自然数,2 x y将a[x]修改为y。
题解:带修改莫队可以解决此题。带修改莫队不会的同学可以先去做下BZOJ2120,然后mex+莫队可以参考BZOJ3585。带修改莫队就是加入了第三关键字time,然后按(左端点所在块,右端点所在块,时间)排序,其中时间指的是在第几次修改操作后。注意修改时要记下原来的数,以便还原回去。维护mex可以对权值分块,如果某块中数的个数==R-L+1,那么这块所有数都出现了,否则暴力扫,我有个同学直接暴力维护也过了。。。
#include<cstdio> #include<cmath> #include<map> #include<cstdlib> #include<algorithm> using namespace std; const int N=200010; struct node{int l,r,id,ans,tim;}q[N]; struct nodee{int x,y,z;}b[N]; int n,m,pos[N],L[N],R[N],a[N],qn,f[N],h[N],g[N],l,r,cnt,c[N]; int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;} bool cmp1(node a,node b){return pos[a.l]<pos[b.l]||pos[a.l]==pos[b.l]&&pos[a.r]<pos[b.r]||pos[a.l]==pos[b.l]&&pos[a.r]==pos[b.r]&&a.tim<b.tim;} bool cmp2(node a,node b){return a.id<b.id;} void add(int x) { if (--f[h[a[x]]]==0) g[pos[h[a[x]]]]--; h[a[x]]++; if (++f[h[a[x]]]==1) g[pos[h[a[x]]]]++; } void del(int x) { if (--f[h[a[x]]]==0) g[pos[h[a[x]]]]--; h[a[x]]--; if (++f[h[a[x]]]==1) g[pos[h[a[x]]]]++; } void add_time(int k) { int x=b[k].x,y=b[k].y,z=b[k].z; if (x>=l&&x<=r) del(x); b[k].z=a[x]; a[x]=y; if (x>=l&&x<=r) add(x); } void del_time(int k) { int x=b[k].x,y=b[k].y,z=b[k].z; if (x>=l&&x<=r) del(x); a[x]=z; if (x>=l&&x<=r) add(x); } int query() { int i=1; for (int i=1;i<=pos[n];i++) if (g[i]!=R[i]-L[i]+1) break; for (int j=L[i];j<=R[i];j++) if (!f[j]) return j; } int main() { n=read(); m=read(); int blo=pow(n,2.0/3); for (int i=1;i<=n;i++) { pos[i]=(i-1)/blo+1; if (!L[pos[i]]) L[pos[i]]=i; R[pos[i]]=i; } for (int i=1;i<=n;i++) a[i]=read(),c[++cnt]=a[i]; int now=0; for (int i=1;i<=m;i++) { int op=read(),l=read(),r=read(); if (op==1) q[++qn]=(node){l,r,i,0,now}; else b[++now]=(nodee){l,r,0},c[++cnt]=b[now].y; } sort(c+1,c+1+cnt); cnt=unique(c+1,c+cnt+1)-c-1; //for (int i=1;i<=cnt;i++) printf("%d ",c[i]); puts(""); for (int i=1;i<=n;i++) a[i]=lower_bound(c+1,c+1+cnt,a[i])-c; for (int i=1;i<=now;i++) b[i].y=lower_bound(c+1,c+1+cnt,b[i].y)-c; //for (int i=1;i<=n;i++) printf("%d ",a[i]); puts(""); sort(q+1,q+1+qn,cmp1); l=1; r=0; now=0; for (int i=1;i<=qn;i++) { while (r<q[i].r) add(++r); while (r>q[i].r) del(r--); while (l>q[i].l) add(--l); while (l<q[i].l) del(l++); while (now<q[i].tim) add_time(++now); while (now>q[i].tim) del_time(now--); q[i].ans=query(); } sort(q+1,q+1+qn,cmp2); for (int i=1;i<=qn;i++) printf("%d\n",q[i].ans); return 0; }