20170703练习赛比赛总结
来源:互联网 发布:js代码整理 编辑:程序博客网 时间:2024/06/05 10:38
C
思路
- 我们发现对于max直接暴力即可
- 可是对于最小值就没有办法了
- 我们可以二分党派获得的票数
- 可是,由于有5%的限制,直接二分不可行
- 此时我们可以思考一下终态:
- 一定会有一定数量
(c) 的党派有一定(x) 数量席位
- 一定会有一定数量
- 想到这里,我们可以通过枚举
c 再二分x
/* 思路:对于最大值,我们只需要把多的票都给它即可 对于最小值,我们可以先枚举有多少个党派可以有席位之后二分最小席位即可 在二分时,我们直接先把x强行填成mid票 之后再每一次选举时,如果x要获得座位时我们都找到一个最小票数投给一个党,把票给他 */ #include<bits/stdc++.h>using namespace std;const int M=105;struct node{ int x,s,i; bool operator<(const node&A)const{ if(x*A.s!=A.x*s)return x*A.s<A.x*s; return i>A.i; }}A[M],B[M],C[M];int n,m,V,res,mi[M],t,Q[M],limt;void MAX(){ for(int x=1;x<=n;x++){ for(int i=1;i<=n;i++)B[i]=A[i]; B[x].x+=res; for(int c=1;c<=m;c++){ int k=0; for(int i=1;i<=n;i++){ if(B[i].x<limt)continue; if(B[k]<B[i]||(!k))k=i; }B[k].s++; } printf("%d ",B[x].s-1); }puts("");}bool check(int h,int x,int RRR){ /*init*/ for(int i=1;i<=n;i++)C[i]=B[i]; C[x].s=h+1; int cas=m-h; /*模拟选举*/ while(cas--){ int f=0,T=0,ned=0; for(int i=1,y;i<=t;i++){ y=Q[i]; /*找到了较优的人了*/ if(C[x]<C[y]){f=1;C[y].s++;break;} /*找cost小的人了*/ if(C[x].i<C[y].i){ int use=(C[x].x*C[y].s)/C[x].s-C[y].x+1; if((!T)||ned>use)T=y,ned=use; }else{ int use=(C[x].x*C[y].s+C[x].s-1)/C[x].s-C[y].x; if((!T)||ned>use)T=y,ned=use; } } if(!f)RRR-=ned,C[T].s++,C[T].x+=ned; if(RRR<0)return 0; }return 1;}void solve(int x){ if(A[x].x<limt)return; int &ans=mi[A[x].i]; ans=m; /*枚举有几个党派获得席位*/ for(int c=1;c<=n;c++){ /*init*/ for(int i=1;i<=n;i++)B[i]=A[i]; int Res=res;t=0; /*我们取最优的几个让他们获得席位*/ for(int i=n;i>=1&&t<=c;i--)if(i!=x){ Q[++t]=i; if(B[i].x<limt)Res-=limt-B[i].x,B[i].x=limt;/*4个小时!!!!!!*/ } if(Res<0)continue; int L=0,R=ans; while(L<=R){ int mid=L+R>>1; if(check(mid,x,Res))ans=mid,R=mid-1; else L=mid+1; } }}void MIN(){ sort(A+1,A+1+n); for(int i=1;i<=n;i++)solve(i); for(int i=1;i<=n;i++)printf("%d ",mi[i]);}int main(){ scanf("%d %d %d",&V,&n,&m); res=V;limt=(V+19)/20; for(int i=1,x;i<=n;i++){ scanf("%d",&x); res-=x; A[i]=(node){x,1,i}; } MAX(),MIN(); return 0;}
小结
- 对于该类问题,我们可以通过分析终态进行分析,不要拘泥于答案本身,需要挖掘最终答案的形成形式
- 如果对于一些限制条件(也可以是二分)不知道怎么判断是否可行的时候,可以分析权值是怎么变化的以及它的变化因素是什么,从而更加清晰的分析问题。
- 例如该题,我们发现直接判断
x 党派投k 票很困难,我们就可以逆向的考虑,即如何把除了k 票以外的票都给其他党派。于是我们直接把k 票都先给x 党(使他的权值最不优)。
- 例如该题,我们发现直接判断
D
思路
- 很容易发现直接枚举
x 是不可能的 - 此时我们要尝试去枚举一些容易枚举的东西
/* 我们发现每个F(x)都可以表示成x*2^a[0]*3^a[1]*5^a[2]*7^a[3] 因为a[]的组合并不多我们可以通过枚举a[]来计算 此时我们可以套入记忆化搜索来实现加速 */#include<bits/stdc++.h>#define For(i,a,b) for(int i=a;i<=b;++i)using namespace std;typedef long long ll;const int M=20;int pri[]={2,3,5,7},a[4];int fac[10][4]={ {0,0,0,0},{0,0,0,0},{1,0,0,0},{0,1,0,0},{2,0,0,0}, {0,0,1,0},{1,1,0,0},{0,0,0,1},{3,0,0,0},{0,2,0,0} };ll A,B,L,R,Dec[M],dp[M][30][19][13][11];ll DP(int c,ll num){ ll mx=num+Dec[18-c]-1; if(mx<L||num>R)return 0; if(c==18)return !a[0]&&!a[1]&&!a[2]&&!a[3]; bool hav=num>=L&&mx<=R; ll res=0,&ans=dp[c][a[0]][a[1]][a[2]][a[3]]; /*如果L<=[mi,mx]<=R 即随便放都可以 于是我们用记忆化搜索*/ if(hav&&~ans)return ans; for(int i=0<num;i<10;++i){ bool f=1; For(j,0,3)if(a[j]<fac[i][j]){f=0;break;} if(!f)continue; For(j,0,3)a[j]-=fac[i][j]; res+=DP(c+1,i*Dec[17-c]+num); For(j,0,3)a[j]+=fac[i][j]; } /*否则不更新DP的答案*/ if(hav)ans=res; return res;}ll pre(int c,ll pro){ /*pro*pro可能炸掉然后小于0了*/ if(pro*pro<0||pro*pro>B)return 0; if(c==4){ L=(A+pro-1)/pro;R=B/pro; return DP(0,0); } ll res=pre(c+1,pro); a[c]++; res+=pre(c,pro*pri[c]); a[c]--; return res;}int main(){ scanf("%lld%lld",&A,&B); Dec[0]=1; For(i,1,M-1)Dec[i]=Dec[i-1]*10; memset(dp,-1,sizeof(dp)); printf("%lld\n",pre(0,1)); return 0;}
小结
- 枚举信息时要明确枚举的信息再接上其他的算法
- 量化枚举信息可以做到事半功倍的效果
阅读全文
1 0
- 20170703练习赛比赛总结
- 20170531练习赛比赛总结
- 20170702练习赛比赛总结
- 20170606组队赛比赛总结
- 20170709训练赛比赛总结
- 20170711训练赛比赛总结
- 20170712训练赛比赛总结
- 20170715离线赛比赛总结
- 20170723离线赛比赛总结
- 比赛总结
- 比赛总结
- 比赛总结
- 比赛总结
- 比赛总结
- 比赛总结
- 练习,比赛计分
- 比赛练习 长方形
- 省赛组队赛3 比赛总结
- undefined function openssl_get_publickey()
- unity游戏android平台获取粘贴板的文本,实现复制粘贴功能
- try-catch-finally学习
- android textview 文本显示不同颜色
- GsyVideoPlayer视频分析(三)------------全屏实现
- 20170703练习赛比赛总结
- CMOS Sensor 基础知识
- Shiro
- 【Linux基础】select、poll、epoll详解
- 数据结构之数组 笔记
- Android开发系列之浅浅谈Intent
- 跳台阶
- Spring声明式事务管理踩过
- POJ 1386 欧拉路径判断