「模拟8.23」one递推,约瑟夫

前置芝士约瑟夫问题

这样大概就是板子问题了

考场的树状数组+二分的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
",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
",ans);
82     }
83 }
View Code

对于约瑟夫问题

我们可以知道最后的人一定是升到最后的,他在新的队伍里的编号是零(因为只有一个人,从零开始编号)

然后我们从后往前递推,考虑最后胜利者在上一层的编号直到最后编号

我们假设当前层为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
",ans+1);
    }
}
原文地址:https://www.cnblogs.com/Wwb123/p/11399763.html