[uoj728]坏掉的设备2

构造$\{t_{i}\}=10101\cdots $,此时将$10$分别看作$\pm 1$,则其前缀和$\in \{0,1\}$

此时,将两者"乱序归并"后,其对$\{s_{i}\}$前缀和的影响不大,进而有以下构造——

记$a_{i}$为$A$二进制下第$i$位,$\forall i\in [1,60]$依次在$\{s_{i}\}$末尾加入$2+[a_{i}\ne a_{i-1}]$个$a_{i}$(定义$a_{0}=1$)

乱序合并后,维护$s$表示$\{u_{i}\}$的前缀和,每当$|s|\ge 2$则得到下一位(根据$s$的符号)并清空$s=0$

关于上述做法的正确性,证明如下——

归纳证明前$k-1$位正确且第$k$位至少在混合到$\{s_{i}\}$中第1个$a_{k}$后得到

注意到忽略$\{t_{i}\}$时,$1$恰会在最后一个$a_{k}$上得到$,0$恰会在倒数第2个$a_{k}$上得到

在此基础上,$\{t_{i}\}$至多使前者向前一个/后者向后一个,均在$a_{k}$上,进而第$k$位也正确

若在最后一个$a_{k}$上得到,显然仅通过$\{t_{i}\}$无法达到$\pm 2$,因此必然用到$a_{k+1}$

若在倒数第2个$a_{k}$上得到,注意到此时$a_{k}$和$\{t_{i}\}$的下一位相同,同样需要用到$a_{k+1}$

事实上,上述做法本质上即能够确定满足以下条件的$\{s_{i}\}$

条件:每一个极长$01$段的长度为$\ge 3$的奇数(以$1$为开头则该段长度为偶数)

进一步的,考虑以下两个优化——

优化1:在$\{s_{i}\}$末尾不断加入一个与原来末尾不同的字符

结合前面的分析,这样不会使得$s$达到$\pm 2$,进而可以确定额外增加的长度

优化2:在$\{s_{i}\}$开头增加一个1,并将所有$\{s_{i}\}$和$\{t_{i}\}$中的$01$翻转

此时,$\{u_{i}\}$中的第1个字符变为标识符,并对之后的字符做同样的处理

打表可得上述形式且长度$\le 140$的$\{s_{i}\}$个数$\ge 10^{18}$,将这些$\{s_{i}\}$编号即可

 1 #include<bits/stdc++.h>
 2 #include "Anna.h"
 3 using namespace std;
 4 #define N 200
 5 #define ll long long
 6 #define vi vector<int>
 7 int n,len;ll sum,f1[N],f2[N];vi s,t;
 8 int Declare(){
 9     n=140,f1[0]=f2[0]=1,sum=f2[1]=0;
10     for(int i=1;i<n;i++){
11         f1[i]=0;
12         for(int j=3;j<=i;j+=2)f1[i]+=f1[i-j];
13     }
14     for(int i=2;i<n;i++)f2[i]=f1[i]+f2[i-2];
15     for(int i=1;i<n;i++)sum+=(n-i)*f2[i];
16     return n;
17 }
18 void add(int k,int p){
19     for(int i=1;i<=k;i++)s.push_back(p);
20 }
21 pair<vi,vi> Anna(ll A){
22     s.clear(),t.clear();
23     bool flag=0;
24     if (sum<A)A-=sum,flag=1;
25     for(int i=1;i<n;i++){
26         if ((n-i)*f2[i]<A)A-=(n-i)*f2[i];
27         else{
28             for(int j=0;j<n-i;j++)
29                 if (f2[i]<A)A-=f2[i];
30                 else{
31                     len=i+j+1,s.push_back(1);
32                     while (i){
33                         if (f1[i]<A)A-=f1[i],i-=2,add(2,1);
34                         else{
35                             int p=0;
36                             while (i){
37                                 i-=3,add(3,p);
38                                 while (f1[i]<A)A-=f1[i],i-=2,add(2,p);
39                                 p^=1;
40                             }
41                         }
42                     }
43                     for(int k=1;k<=j;k++)s.push_back(s.back()^1);
44                     for(int k=1;k<=len;k++)t.push_back(k&1);
45                     if (flag){
46                         for(int k=0;k<len;k++)s[k]^=1,t[k]^=1;
47                     }
48                     return make_pair(s,t);
49                 }
50         }
51     }
52 }
View Code
 1 #include<bits/stdc++.h>
 2 #include "Bruno.h"
 3 using namespace std;
 4 #define N 200
 5 #define ll long long
 6 #define vi vector<int>
 7 int n,len;ll sum,ans,f1[N],f2[N];vi v;
 8 void init(){
 9     n=140,f1[0]=f2[0]=1,sum=f2[1]=0;
10     for(int i=1;i<n;i++){
11         f1[i]=0;
12         for(int j=3;j<=i;j+=2)f1[i]+=f1[i-j];
13     }
14     for(int i=2;i<n;i++)f2[i]=f1[i]+f2[i-2];
15     for(int i=1;i<n;i++)sum+=(n-i)*f2[i];
16 }
17 ll Bruno(vi u){
18     init();
19     len=(u.size()>>1),ans=1,v.clear();
20     if (!u[0]){
21         ans+=sum;
22         for(int i=0;i<u.size();i++)u[i]^=1;
23     } 
24     int s=0;u.erase(u.begin());
25     for(int i:u){
26         s+=(i ? 1 : -1);
27         if (abs(s)>=2)v.push_back(s==2),s=0;
28     }
29     int leni=2+(v[0]!=1);
30     for(int i=1;i<v.size();i++)leni+=2+(v[i]!=v[i-1]);
31     for(int i=1;i<leni;i++)ans+=(n-i)*f2[i];
32     ans+=(len-leni-1)*f2[leni];
33     for(int i=0,j=0;i<v.size();i=j){
34         if ((i)||(!v[i]))leni-=3,j++;
35         while ((j<v.size())&&(v[i]==v[j]))ans+=f1[leni],leni-=2,j++;
36     }
37     return ans;
38 }
View Code

 

posted @ 2022-04-20 08:36  PYWBKTDA  阅读(96)  评论(0编辑  收藏  举报