2014多校联合八(HDU 4945 HDU 4946 HDU 4948 HDU 4950 HDU 4951 HDU 4952)
来源:互联网 发布:c语言ri什么意思 编辑:程序博客网 时间:2024/05/16 19:25
HDU 4945 2048
题意:给你一堆数字 问有几个子集可以拼出2048
思路:
拼数字的规则相当于让数字乘二 所以不是2^i的数字不会拼出2048 那么这些数可选可不选 即为2^cnt种可能
之后只要计算出有几个子集不可能拼出2048即可 不过简单的直接dp是2048*100000的复杂度的 会TLE
所以要变成先枚举元素 再枚举该种元素个数 再枚举2048种状态 然后利用组合求(组合里需要逆元)
为什么这样快? 因为比如枚举2^5这个元素的时候 最多取2^6个 枚举元素个数被缩小了
注意:题目比较卡时间 所以能少做取模运算就少做
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef __int64 LL;#define mod 998244353#define N 2050#define M 100010int n,m,ans;int num[N],dp[15][N],two[M];LL f[M],g[M];inline void scan_d(int &ret){ char c; ret=0; while((c=getchar())<'0'||c>'9'); while(c>='0'&&c<='9') { ret=(ret<<3)+(ret<<1)+(c-'0'); c=getchar(); }}LL powmod(LL fm,int fn){ LL fans=1; while(fn) { if(fn&1) fans=(fans*fm)%mod; fn=fn>>1; fm=(fm*fm)%mod; } return fans;}int Min(int fa,int fb){ if(fa<fb) return fa; return fb;}int main(){ int cas=1,i,j,k,kk,s,amt; two[0]=1; f[0]=1; for(i=1;i<M;i++) { two[i]=(two[i-1]<<1)%mod; f[i]=f[i-1]*i%mod; } g[0]=1; g[100000]=powmod(f[100000],mod-2); for(i=99999;i>=1;i--) g[i]=g[i+1]*(i+1)%mod; for(;;) { scan_d(n); if(!n) break; for(i=0;i<=11;i++) { num[two[i]]=0; for(j=0;j<2048;j++) dp[i][j]=0; } dp[0][0]=1; ans=0; for(i=1;i<=n;i++) { scan_d(k); num[k]++; } m=num[two[11]]; for(i=0;i<11;i++) { amt=num[two[i]]; m+=amt; s=Min(two[11-i],amt); for(j=0;j<=s;j++) { LL x=f[amt]*g[amt-j]%mod*g[j]%mod; for(k=(j<<i),kk=0;k<2048;k++,kk++) if(dp[i][kk]) { dp[i+1][k]+=dp[i][kk]*x%mod; if(dp[i+1][k]>=mod) dp[i+1][k]-=mod; } } } for(i=0;i<2048;i++) { ans+=dp[11][i]; if(ans>=mod) ans-=mod; } ans=(LL)(two[m]-ans+mod)%mod*two[n-m]%mod; printf("Case #%d: %d\n",cas++,ans); } return 0;}HDU 4946 Area of Mushroom
题意:平面上有许多个人 如果这个人到某个位置的距离严格小于其他人 则这个位置属于这个人 问有几个人拥有的范围是无穷的
思路:
首先只有速度最大的人才可能拥有无穷 因为速度稍小的人总会被速度大的人追上
其次只有凸包上的人才可能无穷 这个用极限可以证明 无穷远处凸包上的点一定会超过凸包内点
最后重合位置且速度都为最大的人一定什么都不拥有
注意:普通凸包模版算出来的凸包忽略的边上的点 要特判一下边上的点
#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using namespace std;double eps = 1e-8;double pi = acos((double) (-1));inline int dcmp(double a) //判断一个double型的符号{ if (fabs(a) < eps) return 0; if (a > 0) return 1; else return -1;}struct point{ double x, y,v; int id,mark; inline point(double _x = 0.0, double _y = 0.0) { x = _x; y = _y; } inline point operator -(const point &b) const { return point(x - b.x, y - b.y); } inline point operator +(const point &b) const { return point(x + b.x, y + b.y); } inline point operator |(const double &b) const { return point(x * b, y * b); } inline double operator ^(const point &b) const { return x * b.y - y * b.x; } inline double operator *(const point &b) const { return x * b.x + y * b.y; } inline void input() { scanf("%lf%lf%lf", &x, &y, &v); mark=0; }};inline bool operator ==(const point &a, const point &b){ return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;}inline double len(point a) //向量的摸{ return sqrt(a * a);}inline double Angle(point a, point b) //两个共起点的向量的夹角!{ double ans = acos((a * b) / len(a) / len(b)); return ans;}inline double jijiao(point v){ return atan2(v.y, v.x);}inline point rote(point a, double rad) //逆时针旋转rad弧度!!{ return point(a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad));}inline int isInteger(double xx) //判断一个double型数是否为整数!!{ return dcmp(xx - int(xx + 0.05)) == 0;}inline double torad(double deg) //角度转换为弧度{ return deg / 180 * pi;}inline double dis(point a, point b) //两点之间的距离{ return sqrt((a - b) * (a - b));}inline point getjiaodian(point p, point v, point q, point w) //前提有唯一交点!!参数方程,v,w都为方向向量,p,q,为两直线上的点,求交点 !{ point u; u = p - q; double t = (w ^ u) / (v ^ w); v.x = t * v.x; v.y = t * v.y; return p + v;}inline double dianToLine(point p, point a, point b) //点到直线的距离{ point v1 = b - a, v2 = p - a; return fabs((v1 ^ v2)) / len(v1); //不取绝对值为有向的!!}inline int isxiangjiao(point a, point b, point c, point d) //判断直线相交,重合,平行!!!{ point aa, bb, cc, dd; aa = b - a; bb = d - c; if (dcmp(aa ^ bb) != 0) return 1; //相交 else { aa = a - d; bb = b - c; cc = a - c; dd = b - d; if (dcmp(aa ^ bb) != 0 || dcmp(cc ^ dd) != 0) return 2; //平行 else return 3; //重合 }}//**************************************************//求凸包!!!inline bool operator<(const point& A,const point& B){ return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0);}inline bool mult(point b,point c,point a) { return dcmp((b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x))>=0;}inline int Graham(point pnt[], int n, point res[]){ int i, len, k = 0, top = 1; sort(pnt, pnt + n); if (n == 0) return 0; res[0] = pnt[0]; if (n == 1) return 1; res[1] = pnt[1]; if (n == 2) return 2; res[2] = pnt[2]; for (i = 2; i < n; i++) { while (top && mult(pnt[i], res[top], res[top-1])) top--; res[++top] = pnt[i]; } len = top; res[++top] = pnt[n - 2]; for (i = n - 3; i >= 0; i--) { while (top!=len && mult(pnt[i], res[top],res[top-1])) top--; res[++top] = pnt[i]; } return top;}//**************************************************point list[5000];//输入的点 ,下标从0开始!!point DD[5000];//输出凸包上的点,下标从0开始!!point f[5000];int ans[5000];int main(){ int T, i, j; int n; int ca=0; while(~scanf("%d",&n)) { if(!n) break; ca++; memset(ans,0,sizeof(ans)); double mav=0; for(i=0;i<n;i++) { list[i].input(); list[i].id=i; mav=max(mav,list[i].v); } if(dcmp(mav)==0) { printf("Case #%d: ",ca); for(i=0;i<n;i++) printf("%d",ans[i]); printf("\n"); continue; } int cnt=0; for(i=0;i<n;i++) { if(dcmp(list[i].v-mav)==0) f[cnt++]=list[i]; } sort(f,f+cnt); for(i=0;i<cnt-1;i++) { if(f[i]==f[i+1]) { f[i].mark=1; f[i+1].mark=1; } } int top=Graham(f,cnt,DD); DD[top]=DD[0]; for(j=0;j<cnt;j++) { if(!f[j].mark) for(i=0;i<top;i++) { double aa=len(f[j]-DD[i]); double bb=len(f[j]-DD[i+1]); double cc=len(DD[i+1]-DD[i]); if(dcmp(cc-aa-bb)==0) { ans[f[j].id]=1; break; } } } printf("Case #%d: ",ca); for(i=0;i<n;i++) printf("%d",ans[i]); printf("\n"); } return 0;}HDU 4948 Kingdom
题意:图中任意两点之间有且仅有一条单向边 求一个顶点序列 使得每次新来一个点的时候 其他点到这个点的距离不超过2
思路:
反着思考 从原图里一个一个减去点 那么满足距离不超过2这个条件的情况下 每次一定减去入度最大点 证明题解里也比较详细 就是 如果入度最大为u点 到u距离为1的点集为w 距离为2的为y 假设v点与u点距离大于2 那么v一定不直接连向w 因此w必须连向v 同时u也必须连向v 那么v入度比u大 产生矛盾
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 510int n;int ans[N],in[N];char maz[N][N];inline void scan_d(int &ret){ char c; ret=0; while((c=getchar())<'0'||c>'9'); while(c>='0'&&c<='9') { ret=(ret<<3)+(ret<<1)+(c-'0'); c=getchar(); }}int main(){ int i,j,k,p; for(;;) { scan_d(n); if(!n) break; for(i=1;i<=n;i++) in[i]=0; for(i=1;i<=n;i++) { scanf("%s",maz[i]+1); for(j=1;j<=n;j++) { if(maz[i][j]=='1') in[j]++; } } for(i=1;i<=n;i++) { k=-1; for(j=1;j<=n;j++) { if(in[j]>k) { k=in[j]; p=j; } } in[p]=-1; ans[i]=p; for(j=1;j<=n;j++) { if(in[j]>0&&maz[p][j]=='1') in[j]--; } } for(i=n;i;i--) printf("%d%s",ans[i],(i!=1)?" ":"\n"); } return 0;}HDU 4950
题意: 略
思路:
水题 判断一下能不能打死 k下能不能打死 k+1下能不能打掉血即可
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef __int64 LL;LL h,a,b,k;int main(){ int t=1; for(;;) { scanf("%I64d%I64d%I64d%I64d",&h,&a,&b,&k); if(!h&&!a&&!b&&!k) break; printf("Case #%d: ",t++); if(h<=a) puts("YES"); else if(a*k-b*(k-1)>=h) puts("YES"); else if(a*k>b*(k+1)) puts("YES"); else puts("NO"); } return 0;}HDU 4951 Multiplication table
题意:给你一张p进制乘法表 现在他把所有的数字都换掉 比如0变成1 3变成8… 问你 新表中0、1、2…分别变成了什么数字…
思路:
0可以特判 一行一列全一样 1也特判 十位全是0变成的数字
其他数字根据十位判断 因为p进制情况下 比如3*x 那么他的十位一定只有3中情况
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 510int a[N][N][2],ans[N],vis[N];int n;inline void scan_d(int &ret){ char c; ret=0; while((c=getchar())<'0'||c>'9'); while(c>='0'&&c<='9') { ret=(ret<<3)+(ret<<1)+(c-'0'); c=getchar(); }}int main(){ int t=1,i,j,k,one,zero; for(;;) { scanf("%d",&n); if(!n) break; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { scan_d(a[i][j][0]); scan_d(a[i][j][1]); } } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) vis[a[i][j][0]]=1; for(j=0,k=0;j<n;j++) { k+=vis[j]; vis[j]=0; } if(k!=1) ans[k]=i; else { for(j=1;j<=n;j++) if(a[i][j][0]!=a[i][j][1]) break; if(j<=n) { ans[1]=i; one=i; } else { ans[0]=i; zero=a[i][1][0]; } } } printf("Case #%d: %d",t++,zero); for(i=1;i<n;i++) printf(" %d",a[ans[i]][one][1]); printf("\n"); } return 0;}HDU 4952 Number Transformation
题意:给你一个n 一个k 一共k个操作 第i次操作将n变成i的倍数中大于等于n的最小值
思路:
每次的n可以拆分成x*i 那么 x'(i+1)>=xi 则 x'>=x-x/(i+1) 我们发现x'是递减的 所以总有尽头 因此暴力维护x' 最后乘k即可
代码:
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;__int64 x,y;int main(){ int t=1,i; for(;;) { scanf("%I64d%I64d",&x,&y); if(!x&&!y) break; for(i=1;i<y;i++) { if(x<i+1) break; x-=x/(i+1); } printf("Case #%d: %I64d\n",t++,x*y); } return 0;}
- 2014多校联合八(HDU 4945 HDU 4946 HDU 4948 HDU 4950 HDU 4951 HDU 4952)
- 2014多校联合六(HDU 4923 HDU 4925 HDU 4927 HDU 4930)
- 2014多校联合七(HDU 4937 HDU 4938 HDU 4939 HDU 4941)
- 2014多校联合十(HDU 4972 HDU 4973 HDU 4974 HDU 4975)
- hdu
- hdu
- HDU
- hdu ()
- hdu
- hdu
- HDU
- HDU
- hdu
- hdu
- HDU
- Hdu
- hdu
- hdu-
- 常用控件RadioButton/CheckBox/Toast
- Keepalived
- 软件安装指南
- apache 403异常 You don't have permission to access on this server
- 程序员生存定律
- 2014多校联合八(HDU 4945 HDU 4946 HDU 4948 HDU 4950 HDU 4951 HDU 4952)
- 038
- java中private, public,protected的区别
- 大学新生看过来:如何将笔记本变WiFi热点
- Php面向对象—静态成员
- 对于学校泳池的使用
- linux 远程连接windows
- 第十四章 监控管理
- LightOJ 1110 An Easy LCS dp基础