Codeforces Round #158 (Div. 2)
这场的模拟题真的有du!!!
Problem A
水题,更新当前对b取模后的余数,直接模拟。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=2*1e5; int a,b,n; char s[N]; int main() { scanf("%d%d%d",&a,&b,&n); int now=a%b; bool flag=true; int pos=0; for(int i=1;i<=n;i++) { bool judge=false; for(int j=9;j>=0;j--) { if(((now*10)+j)%b==0) { judge=true; now=0; s[pos++]='0'+j; break; } } if(!judge) flag=false; } s[pos]=0; if(flag) printf("%d%s\n",a,s); else puts("-1"); return 0; }
Problem B
看到第一眼,我不想做了!直接跳到了第三题,其实还好,做完第三题后一发就A了。
题目大意:给你一串字符串,让你找出出现次数最多的日期,形式 xx-yy-zzzz,且年份
在2013-2015之间。
思路:我的写法是开一个vis[6][13][32]的数组记录日期出现过的次数,最后找出最大
的一个就好了。在找的时候我先找的中间的月份,在向前向后延伸找,其实是可以直接
十个字符十个字符找,更简单一点。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; const int N=1e5+3; const int d_m[]={0,31,28,31,30,31,30,31,31,30,31,30,31}; char s[N]; int vis[6][13][32],len; void work(int x,int y,int m) { if(x<=0 || y>len) return; if(s[x]!='-' && s[x+1]!='-') { int now=10*(s[x]-'0')+(s[x+1]-'0'); if(now<=d_m[m]) { if(s[y-3]=='2' && s[y-2]=='0' && s[y-1]=='1' && s[y]>='3' && s[y]<='5') vis[s[y]-'0'][m][now]++; else return; } else return; } else return; } int main() { scanf("%s",s+1); len=strlen(s+1); for(int i=1;i+3<=len;i++) { if(s[i]=='-' && s[i+3]=='-' && ((s[i+1]=='0' && s[i+2]>='1' && s[i+2]<='9') || (s[i+1]=='1' && s[i+2]>='0' && s[i+2]<='2'))) { //printf("%d %c^^^^^\n",i,s[i]); int m=10*(s[i+1]-'0')+(s[i+2]-'0'); work(i-2,i+7,m); } } int ansv=0,ansy=0,ansm=0,ansd=0; for(int i=3;i<=5;i++) { for(int j=1;j<=12;j++) { for(int k=1;k<=d_m[j];k++) { if(vis[i][j][k]>ansv) { ansv=vis[i][j][k]; ansy=i; ansm=j; ansd=k; } } } } if(ansd<10) printf("0%d-",ansd); else printf("%d-",ansd); if(ansm<10) printf("0%d-",ansm); else printf("%d-",ansm); printf("201%d\n",ansy); return 0; }
Problem C
题目大意:有n个箱子,每个箱子里有若干个小球(可以为0个),有一个操作,选取
一个箱子i(这个箱子里的小球不能为0),将里面的小球全部都拿出来,一次一个分给
i+1,i+2...,超过n则分给1,2,3...一直循环知道小球分完,现在给你分完之后各个箱子里的
小球个数,和最后一个小球分给了哪个箱子x,让你输出原来箱子里德小球数。
思路:刚开始我以为题目的意思是每个箱子里都至少有一个小球,那么起始位置肯定是
分完之后最少的那个,然后全部箱子里的小球减去最小值,从起始点开始模拟。wa了几次
因为箱子里的小球个数可能为0,可以有多个最小值,这样的话,我们可以将各个小球的
值减去都减去最小值(也就是分小球分过的完整轮数),然后从x从后往前模拟就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; ll a[100005],mn,n,m; int main() { mn=1e18; scanf("%I64d%I64d",&n,&m); for(int i=1;i<=n;i++) { scanf("%I64d",&a[i]); mn=min(mn,a[i]); } for(int i=1;i<=n;i++)a[i]-=mn; ll sum=n*mn; while(a[m]) { a[m]--; m--;sum++; if(m==0)m=n; } a[m]=sum; for(int i=1;i<=n;i++) printf("%I64d%c",a[i],n==i? '\n':' '); return 0; }
Problem D
题目大意:有一棵树,每条边有一个权值,节点的权值等于连接它的各个边的权值的和,
每个点是黑色或者白色,相邻节点的颜色不能一样。现在只给你,节点的颜色和权值,
让你求各个边的情况。
思路:我们先将黑的节点都放一起,白节点也都放一起,然后从小到大排序,每次从
两堆中分别取出一个,定点权值小的那个肯定是端点,将这两个连边,边的权值为较小
的节点权值,较大节点继续留下和另一个不同颜色的点比较,一直这样构造下去。
我好菜啊,没写出来。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define pb push_back #define mp make_pair #define P pair using namespace std; int n; vector<P<int,int> > V[2]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int c,s; scanf("%d%d",&c,&s); V[c].pb(mp(s,i)); } sort(V[0].begin(),V[0].end()); sort(V[1].begin(),V[1].end()); for(int i=0,j=0;i<V[0].size() && j<V[1].size();) { int mn=min(V[0][i].first,V[1][j].first); V[0][i].first-=mn;V[1][j].first-=mn; printf("%d %d %d\n",V[0][i].second,V[1][j].second,mn); if(V[0][i].first) j++; else if(V[1][j].first) i++; else if(i+1<V[0].size()) i++; else j++; } return 0; }
Problem E
题目大意:给你一堆点和9个数字(这九个数字的和为点的总数)让你用平行于x轴的两条线
和平行于y轴的两条线将这些点分为九分,使其与9个数字的任意一种排列一一对应,问你
有没有这样的一种分法,这题补了好久,我好菜。
题解:大体思路是先枚举九个数字的每一种排列,然后判断这种排列可不可行。在判断
每一种排列可不可行的时候,我们可以先判断三行三列的情况,然后再判断其他块中的
点的数量,这样我们就需要一个工具来快速地知道一个区域内有多少点,这样我们就能
想到用线段树,以x轴建树,每个节点存y的值,并将这个节点所对应区间的y的值排序。
详细看代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define pii pair<int,int> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define fi first #define se second using namespace std; const int N=1e5+10; pii p[N];//存点 vector<int> st[N<<2];//建树 int x[N],y[N],n,ax[3],ay[3],b[10],id[10],a[10];//x[N]所有点x的值,y[N]同理; void build(int l,int r,int rt) { for(int i=l;i<=r;i++) st[rt].push_back(p[i].se); sort(st[rt].begin(),st[rt].end()); if(l==r) return; int m=(l+r)>>1; build(lson); build(rson); } int query(int x,int y,int l,int r,int rt) { if(p[l].fi>x) return 0; if(p[r].fi<=x) { return upper_bound(st[rt].begin(),st[rt].end(),y)-st[rt].begin(); } int m=(l+r)>>1; return query(x,y,lson)+query(x,y,rson); } bool judge() { int sx[3],sy[3];sx[0]=0,sy[0]=0; sx[1]=a[1]+a[4]+a[7];sx[2]=sx[1]+a[2]+a[5]+a[8]; sy[1]=a[1]+a[2]+a[3];sy[2]=sy[1]+a[4]+a[5]+a[6]; for(int i=1;i<=2;i++) { if(x[sx[i]]==x[sx[i]+1]) return false;//如果x[sx[i]]==x[sx[i]+1],因为这两个点相等,不能成功分开,这种排列错误; if(y[sy[i]]==y[sy[i]+1]) return false;//同上 } int fx[3],fy[3]; for(int i=1;i<=2;i++) fx[i]=x[sx[i]],fy[i]=y[sy[i]]; if(query(fx[1],fy[1],1,n,1)!=a[1]) return false;//线段树快速询问; if(query(fx[1],fy[2],1,n,1)!=a[1]+a[4]) return false; if(query(fx[2],fy[1],1,n,1)!=a[1]+a[2]) return false; if(query(fx[2],fy[2],1,n,1)!=a[1]+a[2]+a[4]+a[5]) return false; for(int i=1;i<=2;i++) ax[i]=fx[i],ay[i]=fy[i]; return true; } /* a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9] */ int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&p[i].fi,&p[i].se); x[i]=p[i].fi;y[i]=p[i].se; } sort(p+1,p+n+1);sort(x+1,x+1+n);sort(y+1,y+1+n);//排序 for(int i=1;i<=9;i++) scanf("%d",&b[i]),id[i]=i; build(1,n,1); do { for(int i=1;i<=9;i++) a[i]=b[id[i]]; if(judge())//判断这种排列可不可行 { printf("%f %f\n",ax[1]+0.5,ax[2]+0.5); printf("%f %f\n",ay[1]+0.5,ay[2]+0.5); return 0; } }while(next_permutation(id+1,id+10));//枚举9个数字的排列情况 puts("-1"); return 0; }