【学习笔记】AGC044/AGC011

Guess the Password

如果 S S S T T T的子序列,那么会返回 ∣ T ∣ − ∣ S ∣ |T|-|S| TS,否则会大于这个值。

那么可以先查询单个字符,选取最小的答案,这个字符一定在 T T T中出现过。这样我们得到了串长。

那么,我们继续询问连续一段相同字符可以得到每个字符的出现次数。

然后用类似归并的过程合并两个字符集不交的子序列,步数为 c n t a + c n t b − 1 cnt_a+cnt_b-1 cnta+cntb1

那么每次找长度最短的两个子序列合并即可。因为 Huffman \text{Huffman} Huffman树的树高不超过 log ⁡ L \log L logL,所以总步数 L log ⁡ L L\log L LlogL

#include<bits/stdc++.h> #define fi first #define se second #define ll long long #define pb push_back #define inf 0x3f3f3f3f using namespace std; int L(inf); char a[62]; struct cmp{ bool operator()(string x,string y){ return x.size()>y.size(); } }; priority_queue<string,vector<string>,cmp>q; int ask(string s){ cout<<'?'<<' '<<s<<endl; int x;cin>>x;return x; } signed main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); for(int i=0;i<26;i++)a[i]='a'+i; for(int i=0;i<26;i++)a[26+i]='A'+i; for(int i=0;i<10;i++)a[52+i]='0'+i; for(int i=0;i<62;i++){ cout<<'?'<<' '<<a[i]<<endl; int x;cin>>x,L=min(L,x); }L++; for(int i=0;i<62;i++){ string s,t(L,a[i]);int x=ask(t); for(int j=1;j<=L-x;j++)s+=a[i]; if(s.size())q.push(s); } while(q.size()>=2){ string a=q.top();q.pop(); string b=q.top();q.pop(); string c;int i=0,j=0; while(i!=a.size()||j!=b.size()){ if(j==b.size())c+=a[i++]; else if(i==a.size())c+=b[j++]; else{ string c2=c;c2+=a[i]; for(int k=j;k!=b.size();k++)c2+=b[k]; if(ask(c2)==L-c2.size())c+=a[i++]; else c+=b[j++]; } }assert(c.size()==a.size()+b.size()); q.push(c); }cout<<'!'<<' '<<q.top()<<endl; }

Increasing Numbers

显然要分析答案的结构。。。

一个递增数可以拆成若干串 1 1 1。。。

然后有一个很仙的转化。。。

因为 111 ⋯ 11 ⏟ i = 1 0 i − 1 9 \underbrace{111\cdots 11}_{i}=\frac{10^i-1}{9} i 11111=910i1

所以 N = ∑ i = 1 n + 1 k i ( 1 0 i − 1 ) 9 N=\sum_{i=1}^{n+1}\frac{k_i(10^i-1)}{9} N=i=1n+19ki(10i1)

k k k表示总的 111 ⋯ 11 111\cdots 11 11111的个数,那么 9 N + k = ∑ i = 1 n + 1 k i 1 0 i 9N+k=\sum_{i=1}^{n+1}k_i10^i 9N+k=i=1n+1ki10i。左边显然是 10 10 10的倍数,那么如果 k k k合法的话 9 N + k 9N+k 9N+k的数位之和应该不超过 k k k,同时我只能把 1 0 i 10^i 10i拆成 10 10 10 1 0 i − 1 10^{i-1} 10i1,那么要求 k k k ∑ i = 1 n + 1 k i \sum_{i=1}^{n+1}k_i i=1n+1ki 9 9 9同余。等式两边模 9 9 9发现这恒成立。

同时我们观察到 k k k不会超过 10 n 10n 10n,那么我们模拟高精度加法就能做到均摊 O ( 1 ) O(1) O(1),总复杂度 O ( n ) O(n) O(n)

Squared Graph

设集合 Z Z Z表示原图中所以大小为 1 1 1的连通块

设集合 X X X表示原图中存在二分图染色的连通块

设集合 Y Y Y表示原图中不存在二分图染色的连通块

考察 ( a , b ) (a,b) (a,b)形成的连通块数目。如果 ( a , b ) (a,b) (a,b) ( c , d ) (c,d) (c,d)是联通的,那么显然 a a a c c c属于同一连通块, b b b d d d属于同一连通块

如果 a ∈ Z a\in Z aZ b ∈ Z b\in Z bZ,那么每对 ( a , b ) (a,b) (a,b)都会单独形成连通块,贡献 n 2 − ( n − Z ) 2 n^2-(n-Z)^2 n2(nZ)2

如果 a ∈ Y a\in Y aY, b ∈ Y b\in Y bY,连通块数目 ∣ Y ∣ 2 |Y|^2 Y2

如果 a ∈ X a\in X aX, b ∈ X b\in X bX,那么每挪动一步 a a a, b b b的颜色都会同时取反,连通块数目 2 ∣ X ∣ 2 2|X|^2 2∣X2

如果 a ∈ X , b ∈ Y a\in X,b\in Y aX,bY,连通块数目 2 ∣ X ∣ ∣ Y ∣ 2|X||Y| 2∣X∣∣Y

复杂度 O ( n ) O(n) O(n)

Half Reflector

从左端飞出去其实只有一种情况,那就是第一个就是 A A A,否则肯定会从右端飞出去。

如果遇到 B B B就直接走过去,如果遇到 A A A就把垫背的反转,然后走过去。

好妙的结论啊。。。

探究一次操作后 i i i的状态。

A A A看成 0 0 0 B B B看成 1 1 1

如果最高位是 0 0 0,那么把最高位反转成 1 1 1

否则 s s s取反并左移一位。(左移会溢出最高位)

这样 2 n 2n 2n次操作后就会把原串全部移走,剩下 01 01 01交替的情况。

如果 n n n是偶数那么循环节是 1 1 1,如果 n n n是奇数那么循环节是 2 2 2

复杂度 O ( n ) O(n) O(n)


__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530106.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(17)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示