2017 Xian ACM Summer Training Warm-up Exercise 1
2017-07-10 09:21
176 查看
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 3
- 计蒜客 ACM-ICPC 2017 Warmup Contest 12
- ACM ICPC 2017 Warmup Contest 8(ACM PolyU International Invitation Contest)
- 【算法渣渣的逆袭之路】summer training warmming up,暑假的集训要开始啦,先来几道题热热身
- ACM ICPC 2017 Warmup Contest 6(ACM Google Cup 2011 Invitational Programming Contest)
- ACM ICPC 2017 Warmup Contest 2(ACM Northeastern European Regional Contest,Northern Subregion 2016)
- 计蒜客ACM ICPC 2017 Warmup Contest 9--C题
- ACM ICPC 2017 Warmup Contest 1
- UPC 2017 Summer Training 5
- 计蒜客ACM ICPC 2017 Warmup Contest 9--B题-Battle Simulation
- ACM ICPC 2017 Warmup Contest 1 F. Fleecing the Raffle
- ACM ICPC 2017 Warmup Contest 1 F. Fleecing the Raffle
- 计蒜客ACM ICPC 2017 Warmup Contest 9--I题-Older Brother
- 2016 UESTC ACM Summer Training Team Selection (2)解题报告
- 2013 ACM/ICPC Asia Regional Online —— Warmup1 1005 Balls Rearrangement
- 2015 SWJTU ACM Summer Training Final Assessment 1st 部分题解
- 2017 ACM 区域赛青岛站(现场赛) K Our Journey of Xian Ends
- 2012 ACM/ICPC Asia Regional Online Warmup-1007
- 2017ecjtu-summer training # 9 HDU 4544
- ACM ICPC 2017 Warmup Contest 1 F. Fleecing the Raffle