第六届福建省大学生程序设计竞赛(FZU2212—FZU2221)
来源:互联网 发布:ncuts算法 编辑:程序博客网 时间:2024/05/10 08:37
Super Mobile Charger
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2212
解题思路:
水题。
AC代码:
#include <iostream>#include <cstdio>#include <algorithm>using namespace std;int a[105];int main(){ int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); for(int i = 0; i < n; ++i){ scanf("%d",&a[i]); a[i] = 100-a[i]; } sort(a,a+n); int cnt = 0; for(int i = 0; i < n && m-a[i] >= 0; ++i){ m -= a[i]; ++cnt; } printf("%d\n",cnt); } return 0;}
Common Tangents(两圆之间的公公切线)
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2213
解题思路:
告诉你两个圆的圆心与半径,要你找出他们的公共切线的个数。
套模板即可。
http://blog.csdn.net/piaocoder/article/details/41649089
AC代码:
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;struct Point{ double x,y; Point(double x = 0,double y = 0):x(x),y(y){} // 构造函数,方便代码编写};typedef Point Vector; //从程序实现上,Vector只是Point的别名struct Circle{ Point c; double r; Circle(Point c,double r):c(c),r(r){} Point getPoint(double a){ return Point(c.x+cos(a)*r,c.y+sin(a)*r); }};//返回切线的条数。-1表示无穷条切线//a[i]和b[i]分别是第i条切线在圆A和圆B上的切点int getTangents(Circle A,Circle B){ int cnt = 0; if(A.r < B.r) swap(A,B); int d2 = (A.c.x-B.c.x)*(A.c.x-B.c.x)+(A.c.y-B.c.y)*(A.c.y-B.c.y); int rdiff = A.r-B.r; int rsum = A.r+B.r; if(d2 < rdiff*rdiff) return 0; //内含 if(d2==0 && A.r==B.r) return -1; //无限条切线 if(d2 == rdiff*rdiff){//内切,1条切线 return 1; } //有外公切线 cnt += 2; if(d2 == rsum*rsum){//一条公切线 ++cnt; } else if(d2 > rsum*rsum){//两条公切线 cnt += 2; } return cnt;}int main(){ int T; scanf("%d",&T); while(T--){ Point p1,p2; double r1,r2; scanf("%lf%lf%lf",&p1.x,&p1.y,&r1); Circle c1(p1,r1); scanf("%lf%lf%lf",&p2.x,&p2.y,&r2); Circle c2(p2,r2); printf("%d\n",getTangents(c1,c2)); } return 0;}
Knapsack problem(动态规划)
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2214
解题思路:
题目大意:
给你一个背包,容量为10^9,物品个数为500,价值和小于5000,求最大价值。
算法思想:
因为容量太大,所以不能按0-1背包问题去求解。注意到物品个数较小,而且价值和最大只有5000,所以可以逆向思维,求得对应价
值下最小的重量,即dp[i]表示总价值为i的最小重量是多少,则dp[j] = min(dp[j] , dp[j-val[i]]+vol[i]);最后从sum(物品总价值开始判
断)开始,找到第一个小于等于b(容量)的v即可。。。
AC代码:
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>#define INF 0x3f3f3f3fusing namespace std;int dp[5005];int w[505],v[505];int main(){ int T; scanf("%d",&T); while(T--){ int n,b; int sum = 0; scanf("%d%d",&n,&b); for(int i = 0; i < n; ++i){ scanf("%d%d",&w[i],&v[i]); sum += v[i]; } for(int i = 1; i <= sum; ++i) dp[i] = INF; dp[0] = 0; for(int i = 0; i < n; ++i){ for(int j = sum; j >= v[i]; --j){ if(dp[j-v[i]] != INF){ dp[j] = min(dp[j],dp[j-v[i]]+w[i]); } } } for(int i = sum; i >= 0; --i){ if(dp[i] <= b){ printf("%d\n",i); break; } } } return 0;}
Simple Polynomial Problem(中缀表达式)
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2215
解题思路:
中缀表达式求值,数字栈存的是多项式。
AC代码:
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;struct Poly{ ll a[1005]; Poly operator + (const Poly &p) const{ Poly tmp = {0}; for(int i = 0; i < 1005; ++i){ tmp.a[i] = (a[i]+p.a[i])%1000000007; } return tmp; } Poly operator * (const Poly &p) const{ Poly tmp = {0}; for(int i = 0; i < 1005; ++i){ if(a[i] == 0) continue; for(int j = 0; j < 1005; ++j){ if(p.a[j] == 0) continue; tmp.a[i+j] += a[i]*p.a[j]; tmp.a[i+j] %= 1000000007; } } return tmp; }}pstk[1005];char ostk[1005] = {'#'};int ptop,otop,pri[350];char str[1005];void push(char op){ if(ostk[otop]=='#' && op=='#') return; if(ostk[otop]=='(' && op==')'){ --otop; return; } if(pri[ostk[otop]]<pri[op] || ostk[otop]=='('){ ostk[++otop] = op; return; } if(ostk[otop--] == '+'){ Poly p = pstk[ptop]+pstk[ptop-1]; ptop -= 2; pstk[++ptop] = p; }else{ Poly p = pstk[ptop]*pstk[ptop-1]; ptop -= 2; pstk[++ptop] = p; } push(op);}void output(Poly &p){ int i = 1000; while(i>=0 && p.a[i] == 0) --i; if(i == -1){ puts("0"); return; } for(int j = i; j >= 0; --j){ printf("%lld",p.a[j]); if(j) putchar(' '); } putchar('\n');}int main(){ pri['+'] = 2; pri['*'] = 3; pri['('] = 4; pri[')'] = 1; pri['#'] = 1; int T; scanf("%d",&T); while(T--){ scanf("%s",str); ptop = 0; otop = 1; for(int i = 0; str[i]; ++i){ if(str[i]>='0' && str[i]<='9'){ Poly p = {0}; p.a[0] = str[i]-'0'; pstk[++ptop] = p; }else if(str[i]=='x'){ Poly p = {0}; p.a[1] = 1; pstk[++ptop] = p; }else{ push(str[i]); } } push('#'); output(pstk[ptop]); } return 0;}
The Longest Straight
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2216
解题思路:
pre[i]代表数字i的前面0的总数目, 对于每个i找出符合条件的j ,使得i-j之间有恰好有m个0,然后更新答案ans。
AC代码:
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N = 100005;int a[N],pre[N];void solve(int n,int m){ for(int i = 1; i <= n; ++i) pre[i] = pre[i-1]+(!a[i]); int ans = 0; int j = 1; for(int i = 1; i <= n; ++i){ for(; j <= n; ++j){ if(pre[j]-pre[i-1] > m) break; } if(j-i > ans){ ans = j-i; } } printf("%d\n",ans);}int main(){ int T; scanf("%d",&T); while(T--){ memset(a,0,sizeof(a)); int x,n,m; scanf("%d%d",&n,&m); int k = 0; for(int i = 0; i < n; ++i){ scanf("%d",&x); if(!x) k++; a[x] = 1; } solve(m,k); } return 0;}
Simple String Problem(状态压缩dp)
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2218
解题思路:
题目大意:
一个长为n(n<=2000)的字符串,由前k(k<=16)个小写字母组成,求两段子串A和B,A和B中间没有共用的字母类型,求len(A)*len(B)
的最大值。
算法思想:
二进制状态压缩,每一位的状态表示第i个字母存在状态,n^2的时可以枚举出所有子串的状态和长度。然后每次与(1<<k - 1)异或就
是不含相同的子串状态。但是不能直接对每一种状态枚举他的子集和异或值,这样太大了,肯定会超时,因此我们可以用dp[tmp]表
示tmp状态所有子集的最大长度。
先状态转移一下,最后遍历所有的状态和其异或状态就可以更新出答案。
AC代码:
#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int N = 2005;char str[N];int dp[(1<<16)+10];int main(){ int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); scanf("%s",str); memset(dp,0,sizeof(dp)); for(int i = 0; i < n; ++i){ int tmp = 0; for(int j = i; j < n; ++j){ tmp |= 1<<(str[j]-'a'); dp[tmp] = max(dp[tmp],j-i+1); } } int len = 1<<m; for(int i = 0; i < len; ++i){ for(int j = 0; j < m; ++j){ if((1<<j) & i) dp[i] = max(dp[i],dp[i^(1<<j)]); } } int ans = 0; for(int i = 0; i < len; ++i){ ans = max(ans,dp[i]*dp[(len-1)^i]); } printf("%d\n",ans); } return 0;}
StarCraft(哈夫曼树+优先队列)
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2219
解题思路:
类似于哈夫曼树的合并方式,对于当个农民(工蜂)来说,算上分裂技能,建造是不断两两并行的,建造时间越小,合并的价值就
越小。合并后的时间去被合并两者的较大值+K。初始农民的数量就是合并的终点。
然后问题就可以化简为,给你一堆数字,每次把次小值+k,再删除当前最小值,直到剩下m个数字。
使用优先队列求解,将默认排序的大根堆,改成小根堆即可。
AC代码:
#include <iostream>#include <cstdio>#include <queue>using namespace std;priority_queue<int,vector<int>,greater<int> > q;int main(){ int T; scanf("%d",&T); while(T--){ int x,n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i = 0; i < n; ++i){ scanf("%d",&x); q.push(x); } while(n > m){ q.pop(); q.push(q.top()+k); q.pop(); --n; } while(q.size() != 1) q.pop(); printf("%d\n",q.top()); q.pop(); } return 0;}
Defender of Argus(优先队列)
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2220
解题思路:
类似于炉石传说中的“ 奥古斯守卫者 ”,不断选取最优解即可。。。
AC代码;
#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;const int N = 100005;int n,k;int a[N],l[N],r[N];bool vis[N];struct node{ int l,r,val; node(int _l,int _r):l(0),r(0){ l = _l; r = _r; val = a[_l]+a[_r]; } bool operator < (const node& no) const{ return val < no.val; }};int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&k); for(int i = 1; i <= n; ++i) scanf("%d",&a[i]); if(n == 0){ if(k == 0 || k == 1) printf("0\n"); else printf("%d\n",4+(k-2)*5); continue; } if(n == 1){ printf("%d\n",a[1]+1+(k-1)*5); continue; } memset(vis,false,sizeof(vis)); for(int i = 1; i <= n; ++i){ l[i] = i-1; r[i] = i+1; } r[0] = 1; l[n+1] = n; priority_queue<node> q; for(int i = 1; i < n; ++i) q.push(node(i,i+1)); bool put = false; int sum = 0,last = n; while(!q.empty() && k > 0){ node cur = q.top(); q.pop(); if(cur.val <= 3 && put == true) break; int ll = cur.l,rr = cur.r; if(vis[ll] || vis[rr]) continue; sum += (a[ll]+a[rr]+2); last -= 2; --k; vis[ll] = true; vis[rr] = true; int _l = l[ll], _r = r[rr]; l[_r] = _l; r[_l] = _r; put = true; if(_l!=0 && _r!= n+1) q.push(node(_l,_r)); } if(k>0 && last==1 && a[r[0]]>3){ sum += a[r[0]] + 2; --k; } sum += k*5; printf("%d\n",sum); } return 0;}
RunningMan
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2221
解题思路:
将跑男n均分为3份,取其中较小两份cnt1,cnt2,如果m>=cnt1+cnt2+2;则跑男不能一定获胜,反之则能。
AC代码:
#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;int main(){ int T; scanf("%d",&T); while(T--){ int n,m; scanf("%d%d",&n,&m); int cnt1 = n/3; n -= cnt1; int cnt2 = n/2; if(cnt1+cnt2+2 <= m) puts("No"); else puts("Yes"); } return 0;}
- 第六届福建省大学生程序设计竞赛(FZU2212—FZU2221)
- 第六届福建省大学生程序设计竞赛
- 第六届福建省大学生程序设计竞赛(几道水题)
- 第六届福建省大学生程序设计竞赛 Problem J RunningMan【数学】
- 第六届福建省大学生程序设计竞赛 Super Mobile Charger
- 第六届福建省大学生程序设计竞赛 Common Tangents
- Common Tangents【第六届福建省大学生程序设计竞赛-重现赛】
- RunningMan【第六届福建省大学生程序设计竞赛-重现赛】
- FOJ 2213 Common Tangents 【第六届福建省大学生程序设计竞赛】
- 第六届福建省大学生程序设计竞赛-重现赛
- 第六届福建省大学生程序设计竞赛——E The Longest Straight(尺取法)
- 第六届福建省大学生程序设计竞赛——G Simple String Problem(状态压缩dp)
- FZU Problem 2221 RunningMan(思维考查)——第六届福建省大学生程序设计竞赛-重现赛
- FZU2273Triangles+(三角形)+第八届福建省大学生程序设计竞赛
- 第四届福建省大学生程序设计竞赛
- 2016 第七届福建省大学生程序设计竞赛
- 第八届福建省大学生程序设计竞赛
- FZU Problem 2213 Common Tangents(简单几何,分类讨论)——第六届福建省大学生程序设计竞赛-重现赛
- html特殊标签关于easyUI的特殊设置
- 单独的 python 脚本文件使用 django 自带的 model
- unix网络编程(五)--IO复用+非阻塞
- Web服务器的工作原理及其相关协议
- 在Eclipse中使用debug调试程序
- 第六届福建省大学生程序设计竞赛(FZU2212—FZU2221)
- 缩放图片并加载到内存中
- qt 与ros 实现UI界面下主线程与子线程双向通信
- 10个随机数和
- 使用jetty-maven-plugin插件进行测试---学习笔记
- select标签option选择
- Demo打包尝试以及初略步骤
- 专家直播间的设计开发
- Comparable与Comparator使用以及区别