您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: