poj2886 Who Gets the Most Candies?
2016-07-17 20:48
393 查看
题意:输入n,k表示n个人,第k个第一个离开圆环,之后n行,每行一个名字和一个数字m,表示从这个人开始顺时针(数字大于0)或逆时针(数字小于0)第m个人离开圆环。每个人离开时会有一个得分,得分=F(离开次序i); F(i)=能整除i的数的个数;求这个人的名字和得分。
思路:首先打表枚举[1,500000]的F(i); 然后模拟求这个人的名字,对于[1,n]中,求出是F(i)最大的i值,模拟i次离开就行了。人数比较多,直接模拟肯定不行,需要借助线段树(树状数组)直接计算出要离开圆环的人的坐标,线段树中维护的是这个区间中还剩下几个人。
很多人都把反素数表打了出来,我直接在代码中计算的,只会耗费大约300MS。
我自己写的(2700MS):
看了别人写的后改进的(1700MS,把反素数表打出来还能再节省300MS):
思路:首先打表枚举[1,500000]的F(i); 然后模拟求这个人的名字,对于[1,n]中,求出是F(i)最大的i值,模拟i次离开就行了。人数比较多,直接模拟肯定不行,需要借助线段树(树状数组)直接计算出要离开圆环的人的坐标,线段树中维护的是这个区间中还剩下几个人。
很多人都把反素数表打了出来,我直接在代码中计算的,只会耗费大约300MS。
我自己写的(2700MS):
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<climits> #include<algorithm> #include<map> #include<vector> #include<queue> #define maxn 510000 using namespace std; struct node { char name[50]; int next; int score; }tp[maxn]; int num[maxn]; struct tree { int l,r; int sum; }tr[maxn*3]; void update(int o,int l,int r,int pos,int v) { int m=(l+r)/2; if(l==r) { tr[o].sum=v; } else { if(pos<=m) update(o*2,l,m,pos,v); else update(o*2+1,m+1,r,pos,v); tr[o].sum=tr[o*2].sum+tr[o*2+1].sum; } } int query(int o,int l,int r ,int ql,int qr) { int m=(l+r)/2; if(ql>qr) return 0; if(ql<=l && r<=qr) return tr[o].sum; int ans=0; if(ql<=m) ans+=query(o*2,l,m,ql,qr); if(m<qr) ans+=query(o*2+1,m+1,r,ql,qr); return ans; } void calcu() { memset(num,0,sizeof(num)); for(int i=1;i<maxn;++i) { for(int j=1 ;j*i<maxn;++j) { num[i*j]++; } } } int _find(int o,int l,int r,int pos) { if(l==r) return l; int m=(l+r)/2; if(tr[o*2].sum>=pos) return _find(o*2,l,m,pos); else return _find(o*2+1,m+1,r,pos-tr[o*2].sum); } int main() { int n,k; calcu(); while(scanf("%d%d",&n ,&k)!=EOF) { int mmax=0,pmax; for(int i=1;i<=n;++i) { if(num[i]>mmax) { mmax=num[i]; pmax=i; } } memset(tr,0,sizeof(tr)); for(int i=0;i<n;++i) { scanf("%s%d",tp[i].name,&tp[i].next); update(1,0,n-1,i,1); } int p=1; int re=query(1,0,n-1,0,n-1); int ans_k; while( p<=pmax) { re-=1; tp[k-1].score=num[p++]; ans_k=k-1; int mov=tp[k-1].next; if(mov>=0) { if(re!=0) mov=mov%re; if(mov==0) mov=re; } else { if(re!=0) mov=-(abs(mov)%re); mov+=re+1; if(re!=0) mov%=re; if(!mov) mov=re; } update(1,0,n-1,k-1,0); int re_l=query(1,0,n-1,0,k-1); int re_r=query(1,0,n-1,k,n-1); if(mov>re_r) { mov-=re_r; } else { mov+=re_l; } k=_find(1,0,n-1,mov)+1; } cout<<tp[ans_k].name<<" "<<tp[ans_k].score<<endl; } }
看了别人写的后改进的(1700MS,把反素数表打出来还能再节省300MS):
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<climits> #include<algorithm> #include<map> #include<vector> #include<queue> #define maxn 510000 using namespace std; struct node { char name[50]; int next; int score; }tp[maxn]; int num[maxn]; struct tree { int l,r; int sum; }tr[maxn*3]; void ini(int o,int l,int r) { if(l==r) { tr[o].sum=1; return ; } if(l>r) return ; tr[o].sum=(r-l)+1; int m=(l+r)/2; ini(o*2,l,m); ini(o*2+1,m+1,r); } void calcu() { memset(num,0,sizeof(num)); for(int i=1;i<maxn;++i) { for(int j=1 ;j*i<maxn;++j) { num[i*j]++; } } } int _find(int o,int l,int r,int pos) { tr[o].sum--; if(l==r) return l; int m=(l+r)/2; if(tr[o*2].sum>=pos) return _find(o*2,l,m,pos); else return _find(o*2+1,m+1,r,pos-tr[o*2].sum); } int main() { int n,k; calcu(); while(scanf("%d%d",&n ,&k)!=EOF) { int mmax=0,pmax; for(int i=1;i<=n;++i) { if(num[i]>mmax) { mmax=num[i]; pmax=i; } } memset(tr,0,sizeof(tr)); for(int i=0;i<n;++i) { scanf("%s%d",tp[i].name,&tp[i].next); } ini(1,0,n-1); int p=1; int re=n; int ans_pos,pos; while( p<=pmax) { re-=1; pos=_find(1,0,n-1,k)+1; ans_pos=pos-1; tp[pos-1].score=num[p++]; if(re==0) break; int mov=tp[pos-1].next; if(mov>=0) { mov=(k-1+mov)%re; if(mov==0) mov=re; } else { mov=-(abs(mov)%re); mov+=re+1; mov=(mov+k-1)%re; if(mov==0) mov=re; } k=mov; } cout<<tp[ans_pos].name<<" "<<tp[ans_pos].score<<endl; } }
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- [数论]poj2635__The Embarrassed Cryptographer
- [二分图匹配]poj2446__Chessboard
- POJ1050 最大子矩阵和
- 用单调栈解决最大连续矩形面积问题