CF#386(Div.2) 解题报告
来源:互联网 发布:轻而易举的软件多少钱 编辑:程序博客网 时间:2024/04/30 04:44
A
题意
给出
数据范围
题解
随便乱搞搞…
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #include<ctime> using namespace std; int a,b,c,ans; int main() { scanf("%d%d%d",&a,&b,&c); for (int i=a;i>=1;--i) if (i*2<=b&&i*4<=c) {ans=i+i*2+i*4;break;} printf("%d\n",ans); }
B
题意
一个长度为
数据范围
题解
根据奇偶的不同加加减减
随便乱搞搞…
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #include<ctime> using namespace std; #define N 5005 int n,now; char s[N],ans[N]; int main() { scanf("%d\n",&n);gets(s+1); now=(n-1)/2+1; for (int i=1;i<=n;++i) { ans[now]=s[i]; if (n%2==0) { if (i%2) now+=i; else now-=i; } else { if (i%2) now-=i; else now+=i; } } for (int i=1;i<=n;++i) putchar(ans[i]); putchar('\n'); }
C
题意
数据范围
题解
很显然这道题只是比较人和车谁跑得快而已…
那么根据
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #include<ctime> using namespace std; int s,x1,x2,t1,t2,p,d,ans1,ans2,ans; int main() { scanf("%d%d%d",&s,&x1,&x2); scanf("%d%d",&t1,&t2); scanf("%d%d",&p,&d); if (x1==x2) { puts("0"); return 0; } if (x1<x2) { ans1=(x2-x1)*t2; if (d==1) { if (p<=x1) ans2=(x2-p)*t1; else ans2=(s-p+s+x2)*t1; } else ans2=(p+x2)*t1; } else { ans1=(x1-x2)*t2; if (d==1) ans2=(s-p+s-x2)*t1; else { if (p>=x1) ans2=(p-x2)*t1; else ans2=(p+s+s-x2)*t1; } } ans=min(ans1,ans2); printf("%d\n",ans); }
D
题意
给出a个‘G’b个‘B’共n个字母,将他们排列,问是否存在一种方案使得这两个字母连续都不超过k个。
数据范围
题解
构造体吖
首先如果a=b特判
然后先将所有少的分散来放,再将多的塞在中间,都只塞一个,形成类似GBGBG这种形状,然后再把多余的多的塞到可以塞的位置,要保证合法。这样做可以防止之前放多了后来不够的情况。
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<queue>#include<ctime>using namespace std;#define N 100005int n,k,a,b;bool flag;int cnt[N];char A,B;int main(){ scanf("%d%d%d%d",&n,&k,&a,&b); if (a==b) { for (int i=1;i<=n;++i) if (i%2) putchar('G'); else putchar('B'); putchar('\n'); return 0; } if (a<b) swap(a,b),flag=1; for (int i=1;i<=2*b+1;++i) cnt[i]=1; a-=b+1; for (int i=1;i<=2*b+1;i+=2) { if (a>=k-1) { cnt[i]+=k-1; a-=k-1; } else { cnt[i]+=a; a=0; } if (!a) break; } if (a) { puts("NO"); return 0; } if (!flag) A='G',B='B'; else A='B',B='G'; for (int i=1;i<=2*b+1;++i) { if (i%2) { while (cnt[i]--) putchar(A); } else { while (cnt[i]--) putchar(B); } } putchar('\n');}
E
题意
给出一列n个数,问能否从1~m这些数中选出一些数替换掉这n个数中的若干数使得这n个数中奇数和偶数的个数相等并且没有重复出现的数。如果可以,输出最少替换个数和方案,否则-1.
数据范围
题解
其实这道题没什么难的,就是有点麻烦。
首先统计出来要换多少个数,然后分奇偶找就可以了。需要注意的是不需要替换的数尽量找大的,这样1~m的限制更容易被满足,是一个贪心的思想。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #include<ctime> using namespace std; #define N 200005 int n,m; struct hp{int val,id;bool flag;}a[N]; int odd[N],even[N],cnt,cnto,cnte,anso[N],anse[N]; int cmpval(hp a,hp b) { return a.val>b.val; } int cmpid(hp a,hp b) { return a.id<b.id; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",&a[i].val),a[i].id=i; sort(a+1,a+n+1,cmpval); a[0].val=0;odd[++odd[0]]=-1;even[++even[0]]=0; for (int i=1;i<=n;++i) if (a[i].val!=a[i-1].val) { if (a[i].val%2) { odd[++odd[0]]=a[i].val; if (odd[0]-1<=n/2) a[i].flag=true; } else { even[++even[0]]=a[i].val; if (even[0]-1<=n/2) a[i].flag=true; } } if (odd[0]-1<=n/2) cnto=n/2-odd[0]+1; if (even[0]-1<=n/2) cnte=n/2-even[0]+1; cnt=cnto+cnte; sort(odd+1,odd+odd[0]+1); sort(even+1,even+even[0]+1); for (int i=2;i<=odd[0];++i) { if (!cnto) break; for (int j=odd[i-1]+2;j<odd[i];j+=2) { anso[++anso[0]]=j; --cnto; if (!cnto) break; } } for (int i=odd[odd[0]]+2;i<=m;i+=2) { if (!cnto) break; anso[++anso[0]]=i; --cnto; } if (cnto) { puts("-1"); return 0; } for (int i=2;i<=even[0];++i) { if (!cnte) break; for (int j=even[i-1]+2;j<even[i];j+=2) { anse[++anse[0]]=j; --cnte; if (!cnte) break; } } for (int i=even[even[0]]+2;i<=m;i+=2) { if (!cnte) break; anse[++anse[0]]=i; --cnte; } if (cnte) { puts("-1"); return 0; } for (int i=1;i<=n;++i) if (!a[i].flag) { if (anso[0]) a[i].val=anso[anso[0]--]; else a[i].val=anse[anse[0]--]; } sort(a+1,a+n+1,cmpid); printf("%d\n",cnt); for (int i=1;i<=n;++i) printf("%d%c",a[i].val," \n"[i==n]); }
F
题意
有
数据范围
题解
这道题可以用左右两个指针来解决,也就是单调地移动区间。
首先脑子正常的人都明白只要在
但是不能跳歌,也就是说如果一首歌无论如何都听不了的话后面的也就听不了了。所以无论何时端点移动的时候都必须满足要么区间里的所有歌都听一半,
这样每一次找最大值和最小值替换的时候就需要用到数据结构来维护,线段树就可以。
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<queue>#include<ctime>using namespace std;#define N 200005int n,w,k;int inf,l,r,sum,val,ans;int a[N],f[N],_f[N],h[N],_h[N];namespace Min{ int minn[N*4]; void update(int now) { if (_h[minn[now<<1]]<=_h[minn[now<<1|1]]) minn[now]=minn[now<<1]; else minn[now]=minn[now<<1|1]; } void build(int now,int l,int r) { int mid=(l+r)>>1; if (l==r) { minn[now]=l; return; } build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(now); } void change(int now,int l,int r,int x) { int mid=(l+r)>>1; if (l==r) { minn[now]=x; return; } if (x<=mid) change(now<<1,l,mid,x); else change(now<<1|1,mid+1,r,x); update(now); } int query(int now,int l,int r,int lrange,int rrange) { if (lrange>rrange) return 0; int mid=(l+r)>>1,ans=0; if (lrange<=l&&r<=rrange) return minn[now]; if (lrange<=mid) { int q=query(now<<1,l,mid,lrange,rrange); if (_h[ans]>_h[q]) ans=q; } if (mid+1<=rrange) { int q=query(now<<1|1,mid+1,r,lrange,rrange); if (_h[ans]>_h[q]) ans=q; } return ans; }}namespace Max{ int maxn[N*4]; void update(int now) { if (_f[maxn[now<<1]]>=_f[maxn[now<<1|1]]) maxn[now]=maxn[now<<1]; else maxn[now]=maxn[now<<1|1]; } void build(int now,int l,int r) { int mid=(l+r)>>1; if (l==r) { maxn[now]=l; return; } build(now<<1,l,mid); build(now<<1|1,mid+1,r); update(now); } void change(int now,int l,int r,int x) { int mid=(l+r)>>1; if (l==r) { maxn[now]=x; return; } if (x<=mid) change(now<<1,l,mid,x); else change(now<<1|1,mid+1,r,x); update(now); } int query(int now,int l,int r,int lrange,int rrange) { if (lrange>rrange) return 0; int mid=(l+r)>>1,ans=0; if (lrange<=l&&r<=rrange) return maxn[now]; if (lrange<=mid) { int q=query(now<<1,l,mid,lrange,rrange); if (_f[ans]<_f[q]) ans=q; } if (mid+1<=rrange) { int q=query(now<<1|1,mid+1,r,lrange,rrange); if (_f[ans]<_f[q]) ans=q; } return ans; }}int main(){ scanf("%d%d%d",&n,&w,&k); for (int i=1;i<=n;++i) scanf("%d",&a[i]); for (int i=1;i<=n;++i) { scanf("%d",&f[i]); _f[i]=f[i]; h[i]=(f[i]-1)/2+1; } memset(_h,127,sizeof(_h));inf=_h[0]; Max::build(1,1,n); Min::build(1,1,n); while (l<=n) { if (l<=r) { val-=a[l]; if (_h[l]!=inf) { sum-=h[l]; int loc=Max::query(1,1,n,l,r); if (loc) { sum-=f[loc]-h[loc]; _f[loc]=0;_h[loc]=h[loc]; Max::change(1,1,n,loc);Min::change(1,1,n,loc); } else ++w; } else sum-=f[l]; } ++l; r=max(r,l-1); while (r<n) { if (w) { if (sum+h[r+1]<=k) { sum+=h[r+1]; _f[r+1]=0;_h[r+1]=h[r+1]; Max::change(1,1,n,r+1); Min::change(1,1,n,r+1); --w; val+=a[++r]; } else break; } else { int loc=Min::query(1,1,n,l,r); if (loc&&f[loc]-h[loc]<f[r+1]-h[r+1]&&sum-h[loc]+f[loc]+h[r+1]<=k) { sum+=f[loc]-h[loc]; _f[loc]=f[loc];_h[loc]=inf; Max::change(1,1,n,loc);Min::change(1,1,n,loc); sum+=h[r+1]; _f[r+1]=0;_h[r+1]=h[r+1]; Max::change(1,1,n,r+1);Min::change(1,1,n,r+1); val+=a[++r]; } else if (sum+f[r+1]<=k) { sum+=f[r+1]; val+=a[++r]; } else break; } } ans=max(ans,val); } printf("%d\n",ans);}
G
题意
构造一棵有
数据范围
题解
怎么又是一道构造题…
首先如果这一层的节点数
最后一层的节点一定都是叶子节点。
那么我们可以计算出来最少的叶子节点有多少个,然后指定一些为一定为叶子节点。然后在剩余的点中建树,如果叶子节点不够的话就把儿子都往一个父亲上连,产生一些叶子节点,如果够了的话就一个儿子连一个父亲。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #include<ctime> using namespace std; #define N 200005 int n,t,k,must,last,now; int a[N],b[N],s[N],f[N]; int main() { scanf("%d%d%d",&n,&t,&k);a[0]=s[0]=1; for (int i=1;i<=t;++i) { scanf("%d",&a[i]); s[i]=s[i-1]+a[i]; if (a[i]<a[i-1]) must+=a[i-1]-a[i],b[i-1]=a[i-1]-a[i]; } must+=a[t]; if (s[t]!=n||must>k) { puts("-1"); return 0; } k-=must; last=1,now=2; for (int i=1;i<=t;++i) { if (k<=a[i-1]-1-b[i-1]) { last+=k; while (last<=s[i-1]-b[i-1]&&now<=s[i]) { f[now]=last; ++now,++last; } while (now<=s[i]) { f[now]=last-1; ++now; } k=0; } else { last+=a[i-1]-1-b[i-1]; while (last<=s[i-1]-b[i-1]&&now<=s[i]) { f[now]=last; ++now,++last; } while (now<=s[i]) { f[now]=last-1; ++now; } k-=a[i-1]-1-b[i-1]; } last=s[i-1]+1; now=s[i]+1; } if (k) { puts("-1"); return 0; } printf("%d\n",n); for (int i=2;i<=n;++i) printf("%d %d\n",f[i],i); return 0; }
- CF#386(Div.2) 解题报告
- CF#384 (Div.2) 解题报告
- CF#398(Div.2) 解题报告
- CF#401(Div.2) 解题报告
- CF#403(Div.2) 解题报告
- CF#410(Div.2) 解题报告
- CF Round 415 Div.2解题报告
- CF #308 Div.2 C题 Vanya and Scales 解题报告
- 0712CF解题报告
- 130720CF解题报告
- 130720CF div2解题报告
- cf 161C 解题报告
- Codeforces Round #149 (Div. 2)解题报告
- Codeforces Round #180 (Div. 2) 解题报告
- Codeforces Round #190 (Div. 2) 解题报告
- Codeforces Round #191 (Div. 2) 解题报告
- Codeforces Round #189 (Div. 2) 解题报告
- Codeforces Round #142 (Div. 2) 解题报告
- keepalived实现Tomcat服务双机热备
- jdk与jre的区别
- oracle 网络访问配置tnsnames.ora文件的路径
- 【BZOJ 1014】[JSOI2008]火星人prefix hash+splay+二分
- Linux下安装、配置、启动Apache
- CF#386(Div.2) 解题报告
- 機器人學總結(4) —— 逆運動學
- CI框架教程3——实现框架前后端分离
- nginx + tomcat 负载均衡
- zookeeper 操作 顺序性如何保证
- gulp的安装教程,使用教程,和简单的自动化任务教程
- 【数据库】使用PLSQL工具时,ORACLE客户端连接串的配置
- Ubuntu崩溃报告工具存在远程代码执行漏洞
- JAVA 网页转图片