poj2886Who Gets the Most Candies?
2016-04-26 22:20
204 查看
链接:http://poj.org/problem?id=2886
题意:给定n,k,然后给定n个坐成环的人的信息:名字和a[i]。第一次先删掉第k个人,然后从这个被删除的人开始数a[i],继续删下一个人,如果a[i]<0向前数,a[i]>0向后数。第i个删掉的人有一个值F[i],F[i]为i的约数个数。最后输出F[i]最大的人的名字和F[i]。如果有多个F[i]最大输出i最小的那个。
分析:首先我们将题目分解成两问,求F[i]和求最大F[i]时删除的人。F[i]为i的约数个数,这个我们可以用O(n)筛法筛素数的时候同时处理出来F[i],因为我们在用O(n)筛法筛x时,如果x为质数显然F[x]=2,如果x为合数那么我们是用x的最小质因子p去筛x的,那么有F[x]=2*F[x/p]并且如果(x/p)%p==0那么F[x]-=F[x/p/p],这个推导方法是将p看成特殊元素去用组合数学求解的,这里不加以详细分析。然后第二问就是求最大的F[i]是删除的是谁了,这是经典的约瑟夫环问题,我们用线段树维护维护就可以了。O(nlogn)。
代码:
#include<map> #include<set> #include<cmath> #include<queue> #include<bitset> #include<math.h> #include<cstdio> #include<vector> #include<string> #include<cstring> #include<iostream> #include<algorithm> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; const int N=500010; const int MAX=1000000100; const int mod=100000000; const int MOD1=1000000007; const int MOD2=1000000009; const double EPS=0.00000001; typedef long long ll; const ll MOD=998244353; const ll INF=10000000010; typedef double db; typedef unsigned long long ull; char s [12]; int n,a ,q ,p ,f ,sum ; void deal(int n) { int i,j,k=0; f[1]=q[1]=1; for (i=2;i<=n;i++) { if (!q[i]) { f[i]=2;a[++k]=i; } for (j=1;j<=k;j++) { if (a[j]*i>n) break ; q[a[j]*i]=1;f[a[j]*i]=2*f[i]; if (i%a[j]==0) { f[a[j]*i]-=f[i/a[j]];break ; } } } } void build(int x,int l,int r) { if (l==r) { sum[x]=1;return ; } int mid=(l+r)>>1; build(2*x,l,mid);build(2*x+1,mid+1,r); sum[x]=sum[2*x]+sum[2*x+1]; } int query(int x,int l,int r,int k) { if (l==r) return l; int mid=(l+r)>>1; if (sum[2*x]>=k) return query(2*x,l,mid,k); return query(2*x+1,mid+1,r,k-sum[2*x]); } void updata(int x,int l,int r,int k) { if (l==r) { sum[x]=0;return ; } int mid=(l+r)>>1; if (sum[2*x]>=k) updata(2*x,l,mid,k); else updata(2*x+1,mid+1,r,k-sum[2*x]); sum[x]=sum[2*x]+sum[2*x+1]; } void add(int a,int b) { for (;a<=n;a+=a&(-a)) p[a]+=b; } int getsum(int a) { int ret=0; for (;a;a-=a&(-a)) ret+=p[a]; return ret; } int main() { int i,m,k,w,mx,ans; deal(500000); memset(p,0,sizeof(p)); while (scanf("%d%d", &n, &k)!=EOF) { for (i=1;i<=n;i++) scanf("%s%d", s[i], &a[i]); ans=mx=0;m=n;build(1,1,n); for (i=1;i<=n;i++) add(i,1); for (i=1;i<=n;i++) { w=query(1,1,n,k);updata(1,1,n,k); if (f[i]>mx) { ans=w;mx=f[i]; } add(w,-1); if (a[w]>0) k=getsum(w)+a[w]; else k=getsum(w)+a[w]+1; if (i==n) break ; m--;k=((k-1)%m+m)%m+1; } printf("%s %d\n", s[ans], mx); } return 0; }
相关文章推荐
- Android APP头像的图标与背景的设置
- Linux 0.11几个重要的切换
- ValueAnimator的使用
- KindEditor编辑器的使用
- 338. Counting Bits
- MySQL 5.7.6 以上版本的 root 密码重置
- 致敬——C语言
- php安装解析
- ZOJ_1122
- 在 OC 中实现消息的转发
- struts2 支持的结果类型
- Spring 注解总结
- 【机器学习】【读后感】(条件)概率模型们的本质:树状、时序到一般性的图
- 数据结构与算法笔记 —— 查找算法及代码实现
- 4.20作业
- python杀进程
- 指针二三事
- WebSocket的C++服务器端实现
- Nginx教程(二) Nginx虚拟主机配置
- oracle物理dg安装:主库创建