poj 2886
题意:
有N个人,顺时针围成一个圈,现指定第K个人先跳出,然后报一个数A,A>0,表示从跳出的人(跳出的人不算)左边第一个人开始的第A个人跳出,A<0,则相反,且之后跳出的人进行相同的步奏,现要求的是第i个人跳出时,满足当前i的因子数最多且因子数一样时越早跳出越好。
解题思路:
首先我们可以算出当前如果有N个人它的反素数(<=N,且因子数最多并且最小),然后当一个人跳出时,我们可以算出这个人得左和右各有多少人,这样我们可以求出当前为A时,下一个人在当前总人数的倒数第几个,然后利用线段树去找对应的位置,并更新即可。
注意:
反素数可以利用dfs求
网站:点击打开链接
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
typedef int int64;
#define MAXN0 500010
#define l1(x) (x<<1)
#define l2(x) (l1(x)+1)
#define r1(x) ((x)>>1)
char na[MAXN0][15];
int way[MAXN0],cnt,p[800];
bool vis[800];
int ans,cnter;
struct yznode{
int num,yz;
};
yznode yzmax[MAXN0];
struct node{
int L,R,C;
void setLRC(int aa,int bb){
L = aa;
R = bb;
// C = cc;
}
};
node TR[MAXN0<<2];
int64 prime[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
void dfs(int64 cur,int64 cnt,int64 power,int64 sub,int n)
{
int64 i;
if(cur>n)
return;
if(cnt==cnter&&cur<ans)
ans=cur;
if(cnt>cnter)
{
ans=cur;
cnter=cnt;
}
int64 p=prime[sub];
for(i=1;i<=power;i++)
{
if(cur*p>n)
break;
dfs(cur*p,cnt*(i+1),i,sub+1,n);
p=p*prime[sub];
}
}
void buildTR(int ind,int L,int R){
TR[ind].setLRC(L, R);
if(L==R){
TR[ind].C = 1;
return;
}
int mid = r1(L+R);
int ind1 = l1(ind);
int ind2 = ind1+1;
buildTR(ind1, L, mid);
buildTR(ind2, mid+1, R);
TR[ind].C = TR[ind1].C+TR[ind2].C;
}
void pushup(int ind,int ind1,int ind2){
TR[ind].C = TR[(ind1)].C+TR[(ind2)].C;
}
//int update(int ind,int K){
// if(TR[ind].L==TR[ind].R){
// if(TR[ind].L==K){
// TR[ind].C = 0;
// }
// return 0;
// }
// int mid = r1(TR[ind].L+TR[ind].R),H=0;
// if(mid>=K){
// H = update(l1(ind),K) + TR[l2(ind)].C;
// // pushup(ind);
// }
// else {
// H = update(l2(ind), K);
//
// }
// pushup(ind);
// return H;
//}
int Query(int ind,int F){
if(TR[ind].L==TR[ind].R){
// TR[ind].C = 0;
TR[ind].C = 0;
return TR[ind].L;
//return 0;
}
int H;
int ind1,ind2;
ind1 = (l1(ind));
ind2 = (ind1+1);
if(TR[ind2].C>=F){
H = Query(ind2,F);
}
else {
H = Query(ind1,F - TR[ind2].C);
}
pushup(ind,ind1,ind2);
return H;
}
void solve(int N,int K){
int ind = ans;
//int nn = yzmax[N].num;
//int cnt = 0;
int tmpN = N;
int tmp0,tmp1,tmp2,tmp3,tmp4,tmp8;
int cc = 1;
--tmpN;
//tmp0 = Query(1,N-K+1);//当前在K右边的总数
//tmp1 = tmpN - tmp0;
if(N!=1){
Query(1, N-K+1);
tmp0 = N - K ;
tmp1 = K - 1;
}
while(cc<ind){
tmp8 = abs(way[K])%tmpN;
if(!tmp8)tmp8+=tmpN;
if(way[K]<0){
if(tmp0==0||tmp1==0){
tmp4 = tmp8;
}
else{
if(tmp8<=tmp1){
tmp4 = tmp0 + tmp8;
}
else {
tmp4 = tmp8 - tmp1;
}
}
}
else {
if(tmp0==0||tmp1==0){
tmp4 = tmpN - tmp8 + 1;
}
else{
if(tmp8<=tmp0){
tmp4 = tmp0 - tmp8 + 1;
}
else {
tmp4 = tmpN + tmp0 - tmp8 + 1 ;
}
}
}
K = Query(1,tmp4);
--tmpN;
//int tmp6 = tmp0;
tmp0 = tmp4 -1;
tmp1 = tmpN - tmp0;
++cc;
}
printf("%s %d\n",na[K],cnter);
}
int main(){
int N,K;
//getpr();
//prepro();
while(scanf("%d%d",&N,&K)!=EOF){
buildTR(1,1,N);
for(int i=1;i<=N;++i){
scanf("%s%d",na[i],&way[i]);
}
cnter = 0,ans = 0;
dfs(1,1,50,0,N);
solve(N,K);
//}
}
return 0;
}