反素数f(x):是指不大与x约数最多的数
反素数的程序见我这篇博客:http://blog.csdn.net/xdu_truth/article/details/8043051
先打表出来反素数,那么我们就可以知道n个人第几个人出来事最大的。
然后就是个约瑟夫环问题,但是这题数据范围较大,所以就要用到线段树查找删除。
CODE:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int p[35] = {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}; int np[35] = {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}; char s[500010][15]; int num[500010]; int ans,n,k; int find(int n) { int l = 0,r = 34; while(l<=r) { int m = r+l>>1; if(p[m]>n) r = m-1; else l = m+1; } return l-1; } int SUM[500001<<2]; void pushup(int rt) { SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1]; } void build(int l,int r,int rt) { if(l == r && l == k){SUM[rt] = 0;return ;} if(l == r){SUM[rt] = 1;return;} int m = r+l >> 1; build(lson); build(rson); pushup(rt); } void update(int p,int l,int r,int rt) { if(l == r){SUM[rt] = 0;ans = l;return;} int m = l+r>>1; if(SUM[rt<<1] >= p){update(p,lson);pushup(rt);} else { p -= SUM[rt<<1]; update(p,rson); pushup(rt); } } int main() { //freopen("input.txt","r",stdin); while(~scanf("%d%d",&n,&k)) { int r = find(n); for(int i=1;i<=n;i++) scanf("%s%d",s[i],&num[i]); int now = k; build(1,n,1); int nn = n-1; ans = k; for(int i=1;i<p[r];i++) { int t = num[ans] > 0 ? num[ans]+now-1:num[ans]+now; t--; while(t<0)t+=nn; t = t%nn; t++; //cout << t<< " "<< endl; now = t; update(t,1,n,1); nn--; } printf("%s %d\n",s[ans],np[r]); } return 0; }