刚看到题第一想法一个人一个人往下推,估计会超时,上网看了一些前辈的算法,发现了反素数这个神奇的东西,然后就保存了一份代码作为模板,求反素数以及其约数的个数,虽然还没有仔细看,但起码以后能用来打表了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long lld;
lld prime[20]={2,3,5,7,11,13,17,19,23,29,31,37,39,41,43,47,53};
lld n;
lld bestcurr,largecnt;//bestcurr 相同最大因数个数中值最小的数,largecnt:n范围内最大的因数个数
void getarcprime(lld curr,int cnt,int limit,int k)
{
if(curr>n)
return ;
if(largecnt<cnt)//此时枚举到的因数个数比之前记录的最大的因数个数要大,就替换最大因数个数
{
largecnt=cnt;
bestcurr=curr;
}
if(largecnt==cnt && bestcurr>curr)//替换最优值
bestcurr=curr;
lld temp=curr;
for(int i=1;i<=limit;i++)
{
temp=temp*prime[k];
if(temp>n)
return;
getarcprime(temp,cnt*(i+1),i,k+1);
}
}
int main()
{
int i,cas,ans;
int a[100],b[100];
ans = 0;
int j = 0;
scanf("%d",&cas);
for(i=1;i<=cas;i++)
{
n = i;
bestcurr=0;
largecnt=0;
getarcprime(1,1,50,0);
if(ans != bestcurr)
{
ans = bestcurr;
a[j] = bestcurr;
b[j++] = largecnt;
}
}
for(int i = 0; i < j; i++)
printf("%d ",a[i]);
printf("\n");
for(int i = 0; i < j; i++)
printf("%d ",b[i]);
return 0;
}
再说这道题,用线段树记录每个位置有没有孩子,记录区间孩子的个数和,然后去寻找孩子原来的位置
假设一开始是k位置的孩子跳出去,然后k这个位置的sum--,代表这里没有孩子了,然后推出下一个该跳出去的孩子是当前的第几个(去掉第k个孩子的当前),然后再用query求出是整个序列的第几个,一直到约数最多的那个数
AC代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#define ls l,m,nod<<1
#define rs m+1,r,nod<<1|1
#define maxn 500010
using namespace std;
struct Node{
int l;
int r;
int sum;
}node[maxn<<2];
int n,k,v[maxn];
int a[37]={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,500001};
int b[37]={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,1314521};
char peo[maxn][11];
void build(int l,int r,int nod){
node[nod].l = l;
node[nod].r = r;
node[nod].sum = r-l+1;
if(l == r) return;
int m = (l + r)>>1;
build(ls);
build(rs);
}
int query(int k,int nod){
node[nod].sum--;
if(node[nod].l == node[nod].r)
return node[nod].l;
if(k <= node[nod<<1].sum)
return query(k,nod<<1);
else
return query(k - node[nod<<1].sum,nod<<1|1);
}
int main()
{
int p,ppp;
while(scanf("%d %d",&n,&k)!=EOF)
{
for(int i = 1; i <= n; i++)
{
scanf("%s %d",peo[i],&v[i]);
}
for(int i = 0; i < 37; i++)
if(a[i] > n)
{
p = a[i - 1];
ppp = b[i-1];
break;
}
build(1,n,1);
int tem;
for(int i = 0; i < p; i++)
{
//printf("k == %d\n",k);
tem = query(k,1);
//printf("tem== %d\n",tem);
n--;
if(n == 0) break;
v[tem] = v[tem] > 0?v[tem]:(v[tem] + 1 + n);
k = (k - 1 -1 + n + (v[tem])%n + n)%n + 1;
}
//int ans = query(k,1);
printf("%s %d\n",peo[tem],ppp);
}
}