这样大概就是板子问题了
考场的树状数组+二分的60分暴力???
1 #include<bits/stdc++.h> 2 #define int long long 3 #define MAXN 11000001 4 int c[MAXN]; 5 int lowbit(int x){return x&(-x);}int n; 6 void add(int x,int k) 7 { 8 for(int i=x;i<=n;i+=lowbit(i)) 9 { 10 c[i]+=k; 11 } 12 } 13 int query(int x) 14 { 15 int ans=0; 16 for(int i=x;i>=1;i-=lowbit(i))ans+=c[i]; 17 return ans; 18 } 19 int second_divied(int l,int r,int x,int last_rs) 20 { 21 22 while(l+1<r) 23 { 24 int mid=(l+r)>>1; 25 if(query(mid)-last_rs<x) 26 { 27 l=mid; 28 } 29 else r=mid; 30 //printf("l=%lld r=%lld\n",l,r); 31 } 32 if(query(l)-last_rs==x)return l; 33 else return r; 34 } 35 int find(int pos) 36 { 37 if(query(n)-query(pos)==0) 38 { 39 return 1ll; 40 } 41 return pos; 42 }int ans=0; 43 void work2() 44 { 45 for(int i=1;i<=n;++i)add(i,1); 46 int sum=0;int pos=0;int cir=1;//上一位置 47 while(sum<n-1) 48 { 49 int now_rs=query(n); 50 int last_rs=query(pos); 51 if(now_rs-last_rs>=cir) 52 { 53 pos=second_divied(pos+1,n,cir,last_rs); 54 add(pos,-1); 55 pos=find(pos); 56 } 57 else if(now_rs-last_rs<cir) 58 { 59 int t=query(n); 60 int me=cir; 61 me=(me-(now_rs-last_rs))%t; 62 if(me==0)me=t; 63 pos=second_divied(1,n,me,0); 64 add(pos,-1); 65 pos=find(pos); 66 } 67 cir++;sum++; 68 } 69 ans=second_divied(1,n,1,0); 70 add(ans,-1); 71 } 72 int T=0; 73 signed main() 74 { 75 scanf("%lld",&T); 76 while(T--) 77 { 78 scanf("%lld",&n); 79 ans=0; 80 work2(); 81 printf("%lld\n",ans); 82 } 83 }
对于约瑟夫问题
我们可以知道最后的人一定是升到最后的,他在新的队伍里的编号是零(因为只有一个人,从零开始编号)
然后我们从后往前递推,考虑最后胜利者在上一层的编号直到最后编号
我们假设当前层为4,编号为3
那么在上一层时因为干掉了一个人,那么就从干掉的人的后一个开始编号
所以上一层是在位置6
这样我们得到f[i]表示在第i次操作后胜利者所处的编号
然后就简单了
#include<bits/stdc++.h> #define MAXN 10000001 using namespace std; int T;int n;int ans=0; signed main() { scanf("%d",&T); while(T--) { scanf("%d",&n); ans=0; for(int i=n-1;i>=1;--i) { ans=(ans+i)%(n-i+1); } printf("%d\n",ans+1); } }
原文:https://www.cnblogs.com/Wwb123/p/11399763.html