2017 Xian ACM Summer Training Warm-up Exercise 1
来源:互联网 发布:阿里云服务器安全设置 编辑:程序博客网 时间:2024/05/22 06:33
A题Chocolate
http://poj.org/problem?id=1322
题意:
c种巧克力,每种数量无穷大,取出n个放桌上,如果出现同种巧克力的就必须两个一起吃掉,即桌面上同种巧克力只能有0个或者1个。问取出n个后剩余m种巧克力的概率。
tip:
方程比较好想,就是dp[i][j]表示一共取了I次,桌子上还有j个的概率,那么
dp[i][j] = dp[i-1][j-1](拿到的是桌子上之前没有的颜色)(c-j+1)/c+dp[i-1][j+1](j+1)/c;
i,j范围都是1e5,那么数组都开不下,1)每个只与i-1项有关,所以可以滚动,且我们知道桌面上同种巧克力不可能出现多余1个,那么就是说j的范围就是100,但是外层循环i 还是会超时,考虑到每层递推都是一样的,可以用构造矩阵,矩阵快速幂即可。
#include <cstdio>#include <iostream>#include <cstring>using namespace std;int c,n,M;const int maxn = 110;struct Matrix{ double m[maxn][maxn];}a;void print(Matrix a){ for(int i = 0 ; i <= 5 ; i++){ for(int j = 0 ; j <= 5 ; j++) printf("%.3f ",a.m[i][j]); printf("\n"); } cout <<"\n";}void get_mar(){ for(int i = 0 ; i <= c ; i++){ for(int j = 0 ; j <= c; j++){ if(i == 0 && j == 1) a.m[i][j] = 1.0; else if(i == c && j == c-1) a.m[i][j] = 1.0; else if(j == i+1 ) a.m[i][j] = (double)(c-j+1)/c; else if(j == i-1) a.m[i][j] =(double) (j+1)/c; else a.m[i][j] = 0.0; } } //print(a);}Matrix Mul_mar(Matrix a,Matrix b){ Matrix p; for(int i = 0 ;i <= c ; i++) for(int j = 0 ; j <= c; j++) p.m[i][j] = 0.0; for(int i = 0 ;i <= c ;i++){ for(int k = 0 ; k <= c ; k++) if(a.m[i][k]) for(int j = 0 ; j <= c ; j++) if(b.m[k][j]) p.m[i][j] = (p.m[i][j]+a.m[i][k]*b.m[k][j]); } return p;}Matrix quick_mar(int n){ Matrix tmp; for(int i = 0 ;i <= c ; i++) for(int j = 0 ; j <= c; j++) tmp.m[i][j] = 0; for(int i = 0 ; i <= c ; i++) tmp.m[i][i] = 1; while(n){ if(n & 1) tmp = Mul_mar(tmp,a); n >>= 1; a = Mul_mar(a,a); } // print(tmp); return tmp;}int main(){ while(~scanf("%d",&c)&&c){ scanf("%d%d",&n,&M); if(M > c){ printf("0.000\n"); continue; } get_mar(); Matrix p = quick_mar(n); printf("%.3f\n",p.m[0][M]); }}
B题Game Prediction :
http://poj.org/problem?id=1323
题意:
有M个人,一人N张牌,每轮牌面最大的人赢(牌面只可能是1~M*N中的一个数且不重复),给出一个人的牌,求其至少能够赢的局数。
##tip:
贪心,最开始觉得题意说的不明确,以为是博弈。。。后来并不知道别人怎么出牌,就只能从大到小,没有比自己大的一定赢了,有的话,手头最大的不一定赢,一直到没有才行
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>int m, n,ca;const int maxn = 1100;int cards[maxn];void sov(){ memset(cards, 0, sizeof(cards)); for(int i = 0; i < n; i++){ int t; scanf("%d", &t); cards[t] = 1; } int lar = 0, ans=0; for(int i = m*n; i > 0; i--){ if(!cards[i]) lar++; else{ if(lar == 0) ans++; else lar--; } } printf("Case %d: %d\n", ++ca,ans);}int main(){ while(~scanf("%d%d",&m,&n) && m && n){ sov(); }}
C题Holedox Moving :
http://poj.org/problem?id=1324
题意:
在n*m的地图上,给出长度为L的蛇身体各个节位置,以及有k个点是墙,问蛇从初始位置走到(1,1)点的最小步数。蛇不能撞墙,不能撞自己的身体。
tip:
看上去像是bfs,遇到问题:状态判重方法和已经每次图形中不可达点都在变。
神奇的hash,对整个图hash是肯定不行得了,考虑对身体hash,固定头的位置,已经身体上每个点对于上一块身体是在上下左右(2进制表达)哪个位置,2进制后,可以用位运算快速的知道移动后身体位置(我们知道后一块是前一快上次在的位置)。
#include <cstdio>#include <iostream>#include <cstring>#include <cmath>#include <queue>using namespace std;int n,m,l,ca;struct node{ int hx,hy; int body[8]; int step;};int len;queue<node> qq;int dirx[]={0,0,1,-1};int diry[]={1,-1,0,0};int mp[22][22];bool state[22][22][1<<14];int trans(int x,int y){ if (x == -1 && y == 0 ) return 1; //shang if (x == 1&&y == 0) return 2; //下 if (x == 0 && y == -1) return 3 ; //左 if (x == 0 &&y == 1) return 4; //右}node get_new(node t,int x,int y){ node res; for (int i = len;i > 1;i--){ res.body[i] = t.body[i-1]; } int dir = trans(t.hx-x,t.hy-y); res.body[1] = dir; res.step = t.step + 1; res.hx = x; res.hy = y; return res;}void get_xy(int &tx,int &ty,int dir,int x,int y){ if (dir == 1)//上 tx = x-1,ty = y; if (dir == 2)//xia tx = x+1,ty = y; if (dir == 3)//zuo tx = x,ty = y-1; if (dir == 4)//you tx = x,ty = y+1;}void deal_map(node t){//body int lastx,lasty; for (int i = 1;i <= len;i++){ int tx,ty; if (i == 1){ get_xy(tx,ty,t.body[i],t.hx,t.hy); } else{ get_xy(tx,ty,t.body[i],lastx,lasty); } lastx = tx; lasty = ty; if (mp[tx][ty] == 0) mp[tx][ty] = 2; }}void un_deal_map(node t){ int lastx,lasty; for (int i = 1;i <= len;i++){ int tx,ty; if (i == 1){ get_xy(tx,ty,t.body[i],t.hx,t.hy); } else{ get_xy(tx,ty,t.body[i],lastx,lasty); } lastx = tx; lasty = ty; if (mp[tx][ty] == 2) mp[tx][ty] = 0; }}int get_body_num(node y){ int ret = 0; for (int i = 1;i <= len;i++){ ret += (y.body[i]-1)* ( 1<<(2*(i-1)) ); } return ret;}void bfs(){ int ans = -1; while(!qq.empty()){ node t=qq.front(); qq.pop(); if (t.hx == 1 && t.hy == 1 ){ ans = t.step; break; } deal_map(t); //设蛇身为障碍 for (int i = 0;i < 4;i++){ int x = t.hx+dirx[i]; int y = t.hy+diry[i]; if (mp[x][y]) continue; //如果不可行 node res = get_new(t,x,y); //移动后得到的新状态res int ret=get_body_num(res); //计算是否出现过当前状态 if (state[res.hx][res.hy][ret] == true) continue; state[res.hx][res.hy][ret]=true; qq.push(res); } un_deal_map(t); //恢复地图 } printf("Case %d: %d\n",++ca,ans);}void init(){ node tm; memset(mp,0,sizeof(mp)); memset(state,0,sizeof(state)); for (int i = 0;i <= m+1;i++) mp[0][i] = 1; for (int i = 0;i <= m+1;i++) mp[n+1][i] = 1; for (int i = 0 ;i <= n+1;i++) mp[i][0]=1; for (int i = 0;i <= n+1;i++) mp[i][m+1] = 1; int xx,yy; int lastx,lasty; int delx,dely; scanf("%d%d",&tm.hx,&tm.hy); for (int i = 1;i <= l-1;i++){ scanf("%d%d",&xx,&yy); if (i == 1) { delx = xx - tm.hx; dely = yy - tm.hy; } else{ delx = xx - lastx; dely = yy - lasty; } tm.body[i] = trans(delx,dely); lastx = xx; lasty = yy; } len = l-1; int num; scanf("%d",&num); for (int i = 1;i <= num;i++) { scanf("%d%d",&xx,&yy); mp[xx][yy] = 1; } tm.step = 0; while(!qq.empty()) qq.pop(); int ret = get_body_num(tm); state[tm.hx][tm.hy][ret]=true; qq.push(tm);}int main(){ while(~scanf("%d%d%d",&n,&m,&l)){ if(n == 0 && m == 0 && l == 0) break; init(); bfs(); }}
D题Machine Schedule :
http://poj.org/problem?id=1325
题意:
有两个机器A和B,A机器有n个模式,B机器有m个模式,两个机器最初在0模式(wa点)
然后有k个作业,每个作业有三个参数i,a,b
i代表作业编号,a和b代表第i作业要么在A机器的a模式下完成【或者】在B机器的b模式下完成
问两个机器总共最少变换多少次可以完成所有作业
tip:
最小点覆盖,等于最大匹配,跑个匈牙利就好啦
#include <cstdio>#include <iostream>#include <cstring>#include <cmath>using namespace std;const int maxn = 10100;int n,m,k,tot,head[maxn];struct node{ int to,next;}edges[maxn];void add(int u,int v){ edges[tot].to = v;edges[tot].next = head[u];head[u] = tot++;}void init(){ memset(head,-1,sizeof(head)); tot = 0; for(int i = 1; i <= k ; i++){ int l,r,jo; scanf("%d%d%d",&jo,&l,&r); if(l == 0 || r == 0) continue; add(l,r+m); }}bool use[maxn];int linker[maxn];bool dfs(int u){ int v; for(int k = head[u]; k != -1; k = edges[k].next){ int to = edges[k].to; if(!use[to]){ use[to] = true; if(linker[to] == -1 || dfs(linker[to])){ linker[to] = u; return true; } } } return false;}void sov(){ int res = 0; memset(linker,-1,sizeof(linker)); for(int i = 1 ; i <= m ; i++){ memset(use,0,sizeof(use)); if(dfs(i)){ res++; } } printf("%d\n",res);}int main(){ while(~scanf("%d",&m)&&m){ scanf("%d%d",&n,&k); init(); sov(); }}
E - Mileage Bank
http://poj.org/problem?id=1326
题意:
给出航线 的长度,经济舱500公里以下算500公里,否则算actual mileage。商务舱算实际里程×1.5。头等舱实际里程×2。根据给出的航班,求出总的mileage bank中的值。
tip:
注意一下字符串结束的方式就好了
#include <cstdio>#include <iostream>#include <cstring>#include <cmath>using namespace std;const int maxn = 11000;char f[maxn],t[maxn],ty[2];int dis,t2,t1,t3,flag;void sov(){ int ans = 0; while(1){ scanf("%s",f); if(f[0] == '#'){ flag = 1; return; } if(f[0] == '0') break; scanf("%s%d%s",t,&dis,ty); if(dis < 500){ t1 = 500; } else t1 = dis; t2 = dis+ (dis%2 == 0? dis/2:(dis+1)/2) ; t3 = dis+dis; // cout <<ty[0]<<" t1 = "<<t1<<" "<<t2<<" "<<t3<<endl; if(ty[0] == 'Y') ans+=t1; else if(ty[0] == 'B') ans+=t2; else ans+=t3; // cout <<"asn = "<<ans<<endl; } printf("%d\n",ans); //if(flag == 1) return;}int main(){ while(1){ sov(); if(flag == 1) break; }}
G题G - Radar Installation:
http://poj.org/problem?id=1328
题意:
假设海岸线是一条无限延伸的直线。陆地在海岸线的一侧,而海洋在另一侧。每一个小的岛屿是海洋上的一个点。雷达坐落于海岸线上,只能覆盖d距离,所以如果小岛能够被覆盖到的话,它们之间的距离最多为d。
题目要求计算出能够覆盖给出的所有岛屿的最少雷达数目。
tip:
每个点到能被x轴管辖的范围就是
t[i].first = x-sqrt(r*r-y*y);
t[i].second = x+sqrt(r*r-y*y);
就变成了最少选多少个点能使得所有区间内都有至少一个点,左端点排序,贪心
#include <cstdio>#include <iostream>#include <cstring>#include <algorithm>#include <cmath>using namespace std;int n;const int maxn = 1100;typedef pair<double,double>pii;pii t[maxn];int ca = 0,flag;double r,x,y;void init(){ flag = 0; for(int i = 0 ; i < n ; i++){ scanf("%lf%lf",&x,&y); if(y > r) flag = 1; t[i].first = x-sqrt(r*r-y*y); t[i].second = x+sqrt(r*r-y*y); } sort(t,t+n);}void sov(){ int ans = 1; double r = t[0].second,l = t[0].first; for(int i = 1 ; i < n ; i++){ if(t[i].second < r ){ r = t[i].second;l= t[i].first; } else if(t[i].first <= r){ l = t[i].first; } else{ l = t[i].first;r = t[i].second; ans++; } } printf("Case %d: %d\n",++ca,ans);}int main(){ while(~scanf("%d%lf",&n,&r)){ if(n == 0 && r == 0) break; if(n == 0){ printf("Case %d: 0\n",++ca); continue; } init(); if(flag == 1){ printf("Case %d: -1\n",++ca); continue; } sov(); }}
- 2017 Xian ACM Summer Training Warm-up Exercise 1
- 2017 Xian ACM Summer Training Warm-up Exercise 3
- 2013 Multi-University Training Contest 1 Warm up HDU 4612
- UPC 2017 Summer Training 1
- UPC 2017 Summer Training 1
- UPC 2017 Summer Training 1
- UPC 2017 Summer Training 1
- UESTC 2017 Summer Training #1 Div.2
- BUPT 2017 summer training (for 16) #1
- 2017 Summer Training Day1
- Summer Training Team Selection (1) Problem F Line Them Up 判断升序降序
- UPC 2017 Summer Training 5
- UPC 2017 Summer Training 5
- BUPT Summer training 1 总结
- 2014 ACM-ICPC Beijing Warm-up (北京赛区热身赛)
- Tutorials for 2014 SWJTU ACM Summer Training Team-PK Contest #1
- 2015 SWJTU ACM Summer Training Final Assessment 1st 部分题解
- Summer Training Team Selection (1) Problem A ACM Contest Scoring 水题
- 栈上分配和TLAB
- AR/VR和AI 再不知道就out了
- 关于mybatis连接数据库异常
- [RK3288][Android6.0] WiFi之无线网络配置的保存过程
- maven中net.sf.json报错的解决方法
- 2017 Xian ACM Summer Training Warm-up Exercise 1
- 为什么Linux内核不允许在中断中休眠?
- Android 蓝牙通信
- 白盒测试、灰盒测试以及黑盒测试的区别
- quartz表达式
- Beautiful Soup写爬虫
- 关于Postgres的oid使用疑问解答.md
- Linux系统实用命令--持续更新中
- 解决SPACE+CTRL没有办法打开或者关闭输入法的问题