题目链接:
https://cn.vjudge.net/problem/POJ-2886
题目大意:
N个人围成一圈第一个人跳出圈后会告诉你下一个谁跳出来跳出来的人(如果他手上拿的数为正数,从他左边数A个,反之,从他右边数A个) 跳出来的人所得到的糖果数量和他跳出的顺序有关 所得的糖果数为 (假设他是第k个跳出的) 则他得到的糖数为k能被多少个数整除
解题思路:
首先将因子个数打表:因子个数打表模板
然后先求出1-n中因子个数最大的为x,约瑟夫环进行x次
用线段树求出每次约瑟夫环后的具体下标。因为随性和约瑟夫环的进行,人在一个一个减少,需要求出约瑟夫环中的第i个在原数组中的下标
#include<iostream>
#include<cstdio>
#define MID(l, r) (l + (r - l) / 2)
#define lson(o) (o * 2)
#define rson(o) (o * 2 + 1)
using namespace std;
typedef long long ll;
const int INF = 1e9 +;
const int maxn = 2e6 + ;
int h, w, n;
struct node
{
int l, r, sum;
}tree[maxn];
int ans[maxn];
void build(int o, int l, int r)
{
tree[o].l = l, tree[o].r = r;
if(l == r)
{
tree[o].sum = ;
return;
}
int m = MID(l, r);
int lc = lson(o), rc = rson(o);
build(lc, l, m);
build(rc, m + , r);
tree[o].sum = tree[lc].sum + tree[rc].sum;
}
int id;
void query(int o, int a)//查询第a个数下标,同时删除这个数
{
if(tree[o].l == tree[o].r)
{
id = tree[o].l;
tree[o].sum = ;
return;
}
int lc = lson(o), rc = rson(o);
if(a <= tree[lc].sum)query(lc, a);
else query(rc, a - tree[lc].sum);
tree[o].sum = tree[lc].sum + tree[rc].sum;
}
int divisor_num[maxn];
void init(int n)
{
for(int i = ; i <= n; i++)
{
divisor_num[i]++;
for(int j = i * ; j <= n; j += i)
divisor_num[j]++;
}
}
int solve(int n)
{
int max = , maxid;
for(int i = ; i <= n; i++)
if(divisor_num[i] > max)
{
max = divisor_num[i];
maxid = i;
}
return maxid;
}
char name[][];
int a[maxn];
int main()
{
int n, m;
init();
while(scanf("%d%d", &n, &m) != EOF)
{
for(int i = ; i <= n; i++)
scanf("%s%d", name[i], &a[i]);
build(, , n);
int ansid = solve(n), mod = n;
int t = ansid;
while()
{
query(, m);
if(--t == )break;
mod--;
if(a[id] > )
{
m = m - + a[id];
m = ((m - ) % mod + mod) % mod + ;
}
else
{
m = m + a[id];
m = ((m - ) % mod + mod) % mod + ;
}
}
printf("%s %d\n", name[id], divisor_num[ansid]);
}
return ;
}