传送门:Josephus Problem
题意:经典约瑟夫问题,有n个人,每次数到第k个人出列,求剩下的最后一人。
分析:用线段树模拟约瑟夫问题,记录区间的减少情况,然后根据每次数到的人在区间排第几位,线段树log(n)找到并更新,总复杂度为O(nlog(n))。
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define N 100010 #define mod 1000000007 #define LL long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; int n,k; int sum[N<<2],vis[N]; void Pushup(int rt) { int ls=rt<<1,rs=ls|1; sum[rt]=sum[ls]+sum[rs]; } void build(int l,int r,int rt) { if(l==r) { sum[rt]=1;return; } int m=(l+r)>>1; build(lson); build(rson); Pushup(rt); } void update(int num,int l,int r,int rt) { if(l==r) { vis[l]=1; sum[rt]=0; return; } int m=(l+r)>>1; if(num<=sum[rt<<1])update(num,lson); else update(num-sum[rt<<1],rson); Pushup(rt); } int main() { int T,cas=1; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&k); memset(vis,0,sizeof(vis)); build(1,n,1); int num=1; for(int i=n;i>1;i--) { num=(num+k-1)%i; if(num==0)num=i; update(num,1,n,1); } for(int i=1;i<=n;i++) if(!vis[i]) { printf("Case %d: %d\n",cas++,i);break; } } }
原文:http://www.cnblogs.com/lienus/p/4381275.html