POJ 2886Who Gets the Most Candies? 线段树+反素数求因子个数最多
2016-08-08 13:55
302 查看
点击打开链接
反素数就是 对 x来说约束个数 G(x),如果 对于 i<x 有 G(i)<G(x)
则称x为反素数。
对于 n 个孩子 ,最后拿到最多的糖果就是 小于等于 n 的最大 反素数。但是 是哪个孩子并不知道,那么就要进行模拟
对于 k 位置的 孩子,他的 数字是 +num 那么因为他自己本身是要被踢走的,所以相对位置 为k= k+num-1
如果数字是 -num,那么按正着数就没影响,k=k-num。线段树存储当前区间共有多少个人,每一次找到第k (前面有k-1个)个孩子,经过的区间都要 -1,然后记录被踢走的孩子编号
///反素数打表
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#define LL long long
#define INF 0x3f3f3f3f
#define lson L,mid,ind<<1
#define rson mid+1,R,ind<<1|1
using namespace std;
const int N=2010000;
int sum
;
void pushup(int ind){
sum[ind]=sum[ind<<1]+sum[ind<<1|1];
}
void build(int L,int R,int ind){
sum[ind]=R-L+1;
if(L==R){
return ;
}
int mid=L+(R-L)/2;
build(lson);
build(rson);
}
int update(int d,int L,int R,int ind){
sum[ind]--;
if(L==R){
return L;
}
int mid=L+(R-L)/2;
if(d<=sum[ind<<1]) return update(d,lson);
else return update(d-sum[ind<<1],rson);
}
bool vis
;
int fprim
,num;
void init(){
num=0;
memset(fprim,0,sizeof(fprim));
for(int i=1;i<=500001;i++){
fprim[i]++;
for(int j=i*2;j<=500001;j+=i){
fprim[j]++;
}
}
}
int a
[20],d
;
int main(){
init();
int n,k;
while(~scanf("%d%d",&n,&k)){
build(1,n,1);
int Max=1;
int id=1;
for(int i=1;i<=n;i++){
if(fprim[i]>Max){Max=fprim[i];
id = i;
}
}
// cout<<id<<" "<<Max<<endl;
for(int i=1;i<=n;i++){
scanf("%s%d",a[i],&d[i]);
}
int huan=n;
d[0]=0;
int pos=0;
for(int i=0;i<id;i++){
if(d[pos]>0){
k=((k-1+d[pos]-1)%huan+huan)%huan+1;
}
else k=((k-1+d[pos])%huan+huan)%huan+1;
pos=update(k,1,n,1);
huan--;
}
// cout<<pos<<endl;
printf("%s %d\n",a[pos],Max);
}
return 0;
}
<span style="font-size:18px;">题意:n个熊孩子按顺时针排列,每个人受伤都有一张牌,牌上有一个数字,从第k个孩子开始出队,出队的熊孩子卡上数字是K,则顺时针第k人是下一个出队的,负数则逆时针,第P个出队的会得到的糖果数是p的因子个数,输出得到最多糖果的人和他的糖果数,如果有多个,则输出最先出队的。</span>
<span style="font-size:18px;"> </span>
<span style="font-size:18px;">思路:用线段树来存储整个区间中的剩余人的个数、然后用反素数来找因子数最多的人的出队的序号。</span>
反素数就是 对 x来说约束个数 G(x),如果 对于 i<x 有 G(i)<G(x)
则称x为反素数。
对于 n 个孩子 ,最后拿到最多的糖果就是 小于等于 n 的最大 反素数。但是 是哪个孩子并不知道,那么就要进行模拟
对于 k 位置的 孩子,他的 数字是 +num 那么因为他自己本身是要被踢走的,所以相对位置 为k= k+num-1
如果数字是 -num,那么按正着数就没影响,k=k-num。线段树存储当前区间共有多少个人,每一次找到第k (前面有k-1个)个孩子,经过的区间都要 -1,然后记录被踢走的孩子编号
///反素数打表
void Solve(){ memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++){ ans[i]++; for(int j=2*i;j<=n;j+=i) ans[j]++; } int max=ans[1]; id=1; for(int i=2;i<=n;i++) //找出第几个人跳出获得的糖最多 if(ans[i]>max){ max=ans[i]; id=i; } }
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#define LL long long
#define INF 0x3f3f3f3f
#define lson L,mid,ind<<1
#define rson mid+1,R,ind<<1|1
using namespace std;
const int N=2010000;
int sum
;
void pushup(int ind){
sum[ind]=sum[ind<<1]+sum[ind<<1|1];
}
void build(int L,int R,int ind){
sum[ind]=R-L+1;
if(L==R){
return ;
}
int mid=L+(R-L)/2;
build(lson);
build(rson);
}
int update(int d,int L,int R,int ind){
sum[ind]--;
if(L==R){
return L;
}
int mid=L+(R-L)/2;
if(d<=sum[ind<<1]) return update(d,lson);
else return update(d-sum[ind<<1],rson);
}
bool vis
;
int fprim
,num;
void init(){
num=0;
memset(fprim,0,sizeof(fprim));
for(int i=1;i<=500001;i++){
fprim[i]++;
for(int j=i*2;j<=500001;j+=i){
fprim[j]++;
}
}
}
int a
[20],d
;
int main(){
init();
int n,k;
while(~scanf("%d%d",&n,&k)){
build(1,n,1);
int Max=1;
int id=1;
for(int i=1;i<=n;i++){
if(fprim[i]>Max){Max=fprim[i];
id = i;
}
}
// cout<<id<<" "<<Max<<endl;
for(int i=1;i<=n;i++){
scanf("%s%d",a[i],&d[i]);
}
int huan=n;
d[0]=0;
int pos=0;
for(int i=0;i<id;i++){
if(d[pos]>0){
k=((k-1+d[pos]-1)%huan+huan)%huan+1;
}
else k=((k-1+d[pos])%huan+huan)%huan+1;
pos=update(k,1,n,1);
huan--;
}
// cout<<pos<<endl;
printf("%s %d\n",a[pos],Max);
}
return 0;
}
#include<algorithm> #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<map> #define LL long long #define bug puts("***********"); #define lson L,mid,ind<<1 #define rson mid+1,R,ind<<1|1 using namespace std; const int N=500010; char s[20]; int d; int tree[N*4],n,k; ///反素数表示 因子个数逐渐递增的(最小的数 ) const int antiprime[]={1,2,4,6,12,24,36,48,60,120,180,240,360,720,840, 1260,1680,2520,5040,7560,10080,15120,20160,25200, 27720,45360,50400,55440,83160,110880,166320,221760, 277200,332640,498960,554400,665280 }; ///因子个数 与上面的数是一一对应的。 const int factorNum[]={1,2,3,4,6,8,9,10,12,16,18,20,24,30,32,36,40,48,60, 64,72,80,84,90,96,100,108,120,128,144,160,168,180, 192,200,216,224 }; void Build(int L,int R,int ind){ tree[ind]=R-L+1; if(L==R){ return ; } int mid=(L+R)/2; Build(lson); Build(rson); } int Update(int val,int L,int R,int ind){ tree[ind]--; if(L==R){ return R; } int mid=(L+R)/2; if(val<=tree[ind<<1]) return Update(val,lson); else return Update(val-tree[ind<<1],rson); } struct node{ char s[20]; int d; }A ; int main(){ while(~scanf("%d%d",&n,&k)){ Build(1,n,1); for(int i=1;i<=n;i++){ scanf("%s%d",A[i].s,&A[i].d); } int cnt=0; ///找因子最多的数的下标 while(antiprime[cnt]<=n)cnt++; ///以后自加自减写在外面,写在里面会出错 cnt--; int pos=0; int cna=n; A[0].d=0; ///只要是出队的序列数<=antiprime[cnt]就是因子数最多的(就算是并列关系,此时的数满足最小) ///此处下标为0 表示第一出队的序号。 for(int i=0;i<antiprime[cnt];i++){ ///自己用坐标推推。找规律, if(A[pos].d>0){ k=((k-1+A[pos].d-1)%cna+cna)%cna+1; } else{ k=((k-1+A[pos].d)%cna+cna)%cna+1; } pos=Update(k,1,n,1); cna--; ///人数在减少 } printf("%s %d\n",A[pos].s,factorNum[cnt]); } return 0; }
相关文章推荐
- 【POJ 2886】 Who Gets the Most Candies?(反素数求最大因子数+线段树)
- POJ 1811 Prime Test(大素数判断和素因子分解)
- [poj 2886] Who Gets the Most Candies[线段树][约瑟夫环][反素数]
- POJ-2886 Who Gets the Most Candies? 线段树 + 反素数
- POJ 1811 Prime Test(素数判定Miller-Rabin+素因子分解Pollard-rho)
- POJ 3368 线段树,给定区间求连续不降序列的在该区间内出现最多的数
- POJ 2429 -- miller-rabin素数测试,Pollard_rho素因子分解
- 【POJ 3368】【RMQ 或者 线段树】Frequent values【求出区间内连续出现次数最多的数的次数。】
- poj2886反素数与线段树
- poj 2886 Who Gets the Most Candies?(数据结构:线段树+DFS反素数打表)
- POJ 1811 Prime Test【大素数判定】【素因子分解】
- POJ 1811 Prime Test(大素数判断+大合数素因子分解)
- POJ 1811 Prime Test (大素数判断和素因子分解)
- POJ-3048 求有最大的素数因子的数
- 【ZOJ 1562和 BZOJ 1053】【反素数】【求n以内的因子最多的那个数(即不超过n的最大反素数)】
- (中等) POJ 2886 Who Gets the Most Candies? , 反素数+线段树。
- 线段树单点更新+反素数 poj-2886-Who Gets the Most Candies
- POJ 1811 Prime Test(大素数判断和素因子分解)
- POJ 2886 Who Gets the Most Candies?【线段树单点更新+反素数打表】【好题】
- poj2886 Who Gets the Most Candies?(反素数 + 线段树)