2019牛客暑期多校训练营(第十场)
B.Coffee Chicken(递归)
•题意
定义 S1 = "COFFEE" , S2 = "CHICKEN";
Si = Si-2 + Si-1;
求在 Sn 中,以第 k 个字符开始的连续 10 个字符;
k ≤ min( |Sn| , 1012);
•Code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 5 int n; 6 ll k; 7 ll f[80]; 8 string s[3]; 9 10 string F(ll l,ll r,int pos) 11 { 12 // printf("pos=%d,(%lld,%lld)\n",pos,l,r); 13 if(pos <= 2) 14 return s[pos].substr(l,r-l+1); 15 16 ll mid=f[pos-2]; 17 18 string ans; 19 if(r <= mid) 20 return F(l,r,pos-2); 21 else if(l > mid) 22 return F(l-mid,r-mid,pos-1); 23 else 24 { 25 // ans=F(l,mid,pos-2)+F(1,r-mid,pos-1); 26 ans=F(l,mid,pos-2); 27 ans += F(1,r-mid,pos-1); 28 } 29 return ans; 30 } 31 string Solve() 32 { 33 if(n > 60) 34 n=(n&1 ? 59:60); 35 36 cout<<F(k,min(k+9,f[n]),n)<<endl; 37 } 38 void Init() 39 { 40 s[1]="#COFFEE"; 41 s[2]="#CHICKEN"; 42 f[1]=6; 43 f[2]=7; 44 for(int i=3;i <= 60;++i) 45 f[i]=f[i-1]+f[i-2]; 46 } 47 int main() 48 { 49 Init(); 50 51 int T; 52 cin>>T; 53 while(T--) 54 { 55 cin>>n>>k; 56 Solve(); 57 } 58 }疑惑:
将第 26,27 行代码合并成第 25 行代码;
在递归时,按理说应该是先递归第一个 F(l,mid,pos-2) 然后在递归 F(1,r-mid,pos-1);
但实际输出中间结果的是否,发现,先递归了 F(1,r-mid,pos-1) 在递归了 F(l,mid,pos-2);
虽然最终结果依旧是先递归 F(l,mid,pos-2) 的结果,但是,为什么中间过程不对呢?
(图一) (图二)
图一是未合并 26,27 时的中间过程,pos = 3 后,先调用 pos = 1 再调用 pos = 2;
图二是合并后的中间过程,pos = 3 后,先调用了 pos = 2;
但是两者输出的最终结果却相同,提交后也能 AC,这是为啥????
E.Hilbert Sort(思维 and 坐标变换)
•题意
$k = 1$ $k = 2$ $k = 3$
可以将边长为 2k 的正方形平分成四部分:①左上角②左下角③右下角④右上角;
k 阶希尔伯特曲线可由 k-1 阶希尔伯特曲线推出;
(1)k-1 阶希尔伯特曲线按照主对角线反转得到①部分;
(2)k-1 阶希尔伯特曲线拷贝到②③部分;
(3)k-1 阶希尔伯特曲线按照副对角线反转得到④部分;
如上图所示,分别表示 1阶,2阶,3阶 希尔伯特曲线;
现给出你 n 个坐标和 k,让你根据 k阶 希尔伯特曲线的走向排列给出的 n 个坐标;
•题解
根据递推条件易得,将任意 k 阶希尔伯特曲线划分成四部分①②③④(意义如上所述);
其曲线走向都和 1阶 希尔伯特曲线的走向相同 ①->②->③->④;
对于求解 k 阶希尔伯特曲线的 n 个点的走向可以转化为求解 ①②③④ 对应的 k-1 阶的点的走向;
具体步骤如下;
步骤一:
将当前的点划分成四部分;
步骤二:
对于每一部分的点,根据上述(1)(2)(3)的逆变化将其变化成 k-1 阶对应的坐标;
对于 ①:因为从 k-1阶 到 ① 做的变化为(1),那么,从 ① 到 k-1阶 需要做的变化为将 (x,y) 变为 (y,x);
对于 ②:由(2)可得,只需将 (x,y) 变为 (x-2k-1,y) 即可;
对于 ③:由(2)可得,只需将 (x,y) 变为 (x-2k-1,y-2k-1) 即可;
对于 ④:由(3)可得,只需将 (x,y) 变为 (2k-y+1,2k-1-x) 即可;
步骤三:
根据走向的优先级,优先调用 ① 的 k-1阶,跳转到步骤一,知道 k-1 = 0 为止;
其次调用 ② , ③ , ④ 的 k-1 阶;
•Code
坐标变换1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e6+50; 4 5 int n,k; 6 struct Data 7 { 8 int id; 9 int x,y; 10 }a[maxn]; 11 vector<Data >p; 12 13 void Go(int k,vector<Data >p) 14 { 15 if(p.empty()) 16 return ; 17 if(k == 0) 18 { 19 assert(p.size() == 1); 20 printf("%d %d\n",a[p[0].id].x,a[p[0].id].y); 21 p.clear(); 22 return ; 23 } 24 int siz=1<<(k-1); 25 vector<Data >q[5]; 26 for(int i=0;i < p.size();++i) 27 { 28 int id,x,y; 29 id=p[i].id; 30 x=p[i].x; 31 y=p[i].y; 32 33 if(x <= siz && y <= siz) 34 q[1].push_back(Data{id,y,x}); 35 else if(x > siz && y <= siz) 36 q[2].push_back(Data{id,x-siz,y}); 37 else if(x > siz && y > siz) 38 q[3].push_back(Data{id,x-siz,y-siz}); 39 else 40 q[4].push_back(Data{id,2*siz-y+1,siz-x+1}); 41 } 42 for(int i=1;i <= 4;++i) 43 Go(k-1,q[i]); 44 } 45 int main() 46 { 47 scanf("%d%d",&n,&k); 48 for(int i=1;i <= n;++i) 49 { 50 int x,y; 51 scanf("%d%d",&x,&y); 52 a[i]={i,x,y}; 53 p.push_back(a[i]); 54 } 55 Go(k,p); 56 57 return 0; 58 }疑惑:
加上第 19 行的 assert(p.size() == 1 ) 就能 AC,不加会返回 MLE;
Why ????
•Code2
坐标变换+hash1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 const int maxn=1e6+50; 5 6 int n,k; 7 struct Data 8 { 9 string id; 10 int x,y; 11 bool operator < (const Data &obj)const 12 { 13 return id < obj.id; 14 } 15 }a[maxn]; 16 17 string Go(int x,int y,int k) 18 { 19 if(k == 0) 20 return "0"; 21 22 int siz=1<<(k-1); 23 ll hs=1ll<<(2*k); 24 if(x <= siz && y <= siz) 25 return "1"+Go(y,x,k-1); 26 if(x > siz && y <= siz) 27 return "2"+Go(x-siz,y,k-1); 28 if(x > siz && y > siz) 29 return "3"+Go(x-siz,y-siz,k-1); 30 31 return "4"+Go(2*siz-y+1,siz-x+1,k-1); 32 } 33 int main() 34 { 35 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 36 scanf("%d%d",&n,&k); 37 for(int i=1;i <= n;++i) 38 { 39 int x,y; 40 scanf("%d%d",&x,&y); 41 string id=Go(x,y,k); 42 a[i]={id,x,y}; 43 } 44 sort(a+1,a+n+1); 45 for(int i=1;i <= n;++i) 46 printf("%d %d\n",a[i].x,a[i].y); 47 }参考自rank1代码:👉 TQL;
我是用字符串 hash 的,相比巨巨代码,慢了好多好多:
而巨巨代码的运行时间:
差的也太多了吧,tql,然鹅,hash 这块我并没怎么学过,是时候学学 hash 了;