2014多校联合八(HDU 4945 HDU 4946 HDU 4948 HDU 4950 HDU 4951 HDU 4952)

2024-09-05 03:32

本文主要是介绍2014多校联合八(HDU 4945 HDU 4946 HDU 4948 HDU 4950 HDU 4951 HDU 4952),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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;elsereturn -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; //平行elsereturn 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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1137836

相关文章

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

hdu 3790 (单源最短路dijkstra)

题意: 每条边都有长度d 和花费p,给你起点s 终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。 解析: 考察对dijkstra的理解。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstrin

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d

hdu 1102 uva 10397(最小生成树prim)

hdu 1102: 题意: 给一个邻接矩阵,给一些村庄间已经修的路,问最小生成树。 解析: 把已经修的路的权值改为0,套个prim()。 注意prim 最外层循坏为n-1。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstri

hdu 1285(拓扑排序)

题意: 给各个队间的胜负关系,让排名次,名词相同按从小到大排。 解析: 拓扑排序是应用于有向无回路图(Direct Acyclic Graph,简称DAG)上的一种排序方式,对一个有向无回路图进行拓扑排序后,所有的顶点形成一个序列,对所有边(u,v),满足u 在v 的前面。该序列说明了顶点表示的事件或状态发生的整体顺序。比较经典的是在工程活动上,某些工程完成后,另一些工程才能继续,此时