P5042 丢失的题面

顺序:10 - 1 - 7 - 8 - 9 - 4 - 5 - 6 - 2 - 3

Point 10

读入,特判,输出。

读入的英文意思是让选手输出自己的程序本身,这个题的确存在,但是这题并没有 SPJ ,所以特判一下输出输出文件就好了。

C++ 的atoi函数可以让读入的字符串变成数字以完成其他点的任务。

Point 1

我和其他聚铑做这个点的过程就十分有趣了。

开始,我们使用了大眼观察法观察了一下这个输出,不知道怎么我就看出了将序列每四个字符划分,然后变成若干以0110开头的长度为 4 的 01 串组。发现这些组的大小都在 3 以内,于是我们在 OEIS 上搜了一下这个序列,居然真的找到了:A007413

它的递推方式是三个元素,每次操作 a->abc b->ac c->b 。这道题中这三个字母分别代表 0110 01101001011010011001 。做了一下,发现是对的。

然后观察文件大小发现输出的字符串长度是 \(2^{22}\) 。没细想,写完就过了。

但是为什么是 \(2^{22}\) 呢?

我回头看了一眼,发现输出好像是初始一个 0 字符,每次操作将当前串取反拼接到后面,做 22 次的结果……(鬼知道我当初为啥直接就想每 4 个分组)

然后又看了下 OEIS,发现这个输出本身就是一个数列:A010060。这个序列还有个名字叫做

Thue-Morse Sequence

wikihow中,叙述了这个序列的几种构造方法,除了上述的两种构造方式之外,还可以直接每次操作 0->01 1->10 来构造。

真有趣

但是代码还是用的第一次写的,懒得改了。(by a___)

namespace subtask1{
int n=22;
vector<vector<int>>vec,tmp;
string s[4],ans;
vector<int>to[4];
inline void main(){
int n=20;
to[1]=vector<int>({1,2,3});
to[2]=vector<int>({1,3});
to[3]=vector<int>({2});
vec.push_back(std::vector<int>({1}));
while(n--)
{
for(auto p:vec)
for(auto q:p)tmp.push_back(to[q]);
swap(vec,tmp);tmp.clear();
}
s[1]="0110";
s[2]="01101001";
s[3]="011010011001";
for(auto p:vec)ans+=s[p.size()];
ans.resize(1<<22);
std::cout<<ans<<std::endl;
}
}

Point 7

因为 2~6 个点都没有什么思路,直接来看第 7 个点。

观察了一下输入,发现是一个图,而且边没有边权。观察了一下输出,发现输出只有 0 和 INF 两种数字。于是几乎可以确定是判断图上两点间连通性了。

namespace subtask7{
int fa[100005];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void onion(int x,int y){
x=find(x),y=find(y);
if(x!=y) fa[x]=y;
}
inline void main(int n,int m){
int q=read();
while(n) fa[n]=n,n--;
while(m--) onion(read(),read());
while(q--) puts(find(read())==find(read())?"0":"2139062143");
}
}

Point 8

切完了上面的点,一看这个点也是个图,而且边有边权。大概扫了一下发现这是个随机生成的树,边权也是随的。询问格式是两个点。

再观察输出,发现输出的答案大多都大于 90000。说明是一个答案期望较大的询问。两点间路径和或者乘积不可能,试验了一下异或发现答案溢出 100000,那么或也顺便排除。

傻了吧唧地想了半天,突然有一位聚铑想到,为啥不是最大值呢?

试了一下果然没错。

namespace subtask8{
const int maxn=1e5+10;
int fa[maxn][21],mx[maxn][21],Q,n=100000;
int ecnt,head[maxn],to[maxn<<1],nxt[maxn<<1],v[maxn<<1],dep[maxn];
inline void addedge(int a,int b){
to[++ecnt]=b,nxt[ecnt]=head[a],head[a]=ecnt;
to[++ecnt]=a,nxt[ecnt]=head[b],head[b]=ecnt;v[ecnt]=v[ecnt-1]=read();
}
void dfs(int x,int f){
fa[x][0]=f;dep[x]=dep[f]+1;
for(int i=0;i<18;i++) fa[x][i+1]=fa[fa[x][i]][i],mx[x][i+1]=max(mx[x][i],mx[fa[x][i]][i]);
for(int i=head[x];i;i=nxt[i]){
int u=to[i];
if(u==f)continue;
mx[u][0]=v[i];
dfs(u,x);
}
}
inline int solve(int x,int y){
if(dep[x]<dep[y])swap(x,y);
int ans=0;
for(int i=18;~i;i--) if(dep[fa[x][i]]>=dep[y]) ans=max(ans,mx[x][i]),x=fa[x][i];
if(x==y)return ans;
for(int i=18;~i;i--) if(fa[x][i]!=fa[y][i]) ans=max(ans,max(mx[x][i],mx[y][i])),x=fa[x][i],y=fa[y][i];
ans=max(ans,max(mx[x][0],mx[y][0]));
return ans;
}
inline void main(){
Q=read();
for(int i=1;i<n;i++) addedge(read(),read());
dfs(1,0);
while(Q--) printf("%d\n",solve(read(),read()));
}
}

Point 9

观察了一下输入,发现是个图。

观察了一下输出,发现有 INF 的存在,那么询问可能是让答案尽量小,所以盲猜最小瓶颈路。试了一下,果然是。

kruskal 的并查集和路径最大值都可以用前面的板子。(出题人真良心)

namespace subtask9{
const int maxn=100005,INF=2139062143;
int Fa[100005],fa[maxn][21],mx[maxn][21];
int find(int x){return Fa[x]==x?x:Fa[x]=find(Fa[x]);}
struct edge{
int u,v,val;
inline bool operator < (const edge& zp) const {return val<zp.val;}
}e[maxn<<1];
int ecnt,head[maxn],to[maxn<<1],nxt[maxn<<1],v[maxn<<1],dep[maxn];
inline void addedge(int a,int b,int c){
to[++ecnt]=b,nxt[ecnt]=head[a],head[a]=ecnt;v[ecnt]=c;
to[++ecnt]=a,nxt[ecnt]=head[b],head[b]=ecnt;v[ecnt]=c;
}
void dfs(int x,int f){
fa[x][0]=f;dep[x]=dep[f]+1;
for(int i=0;i<18;i++) fa[x][i+1]=fa[fa[x][i]][i],mx[x][i+1]=max(mx[x][i],mx[fa[x][i]][i]);
for(int i=head[x];i;i=nxt[i]){
int u=to[i];
if(u==f)continue;
mx[u][0]=v[i];
dfs(u,x);
}
}
inline int solve(int x,int y){
if(dep[x]<dep[y])swap(x,y);
int ans=0;
for(int i=18;~i;i--) if(dep[fa[x][i]]>=dep[y]) ans=max(ans,mx[x][i]),x=fa[x][i];
if(x==y)return ans;
for(int i=18;~i;i--) if(fa[x][i]!=fa[y][i]) ans=max(ans,max(mx[x][i],mx[y][i])),x=fa[x][i],y=fa[y][i];
ans=max(ans,max(mx[x][0],mx[y][0]));
return ans;
}
inline void main(){
read();int Q=read();
for(int i=1;i<=100000;i++) Fa[i]=i,e[i].u=read(),e[i].v=read(),e[i].val=read();
sort(e+1,e+100001);
for(int i=1;i<=100000;i++){
int u=find(e[i].u),v=find(e[i].v);
if(u!=v){
Fa[u]=v;
addedge(e[i].u,e[i].v,e[i].val);
}
}
for(int i=1;i<=50000;i++) if(!dep[i]) dfs(i,0);
while(Q--){
int x=read(),y=read();
if(find(x)!=find(y))printf("%d\n",INF);
else printf("%d\n",solve(x,y));
}
}
}

Point 4

后面的全做完了,回头看一眼 01 串和 012 串,没啥思路,直接看第四个。

观察了一下输入输出,发现输入输出都是回文

什么玩意是回文的?

第一个字符大概是 n,发现第一项是 1,第二项是 n。于是有个聚铑很自然地想到是组合数,然后发现输出也是对应的 n 的一行组合数,于是就切了。

拆了一下数,发现模数是 104857601,一个 NTT 模数

namespace subtask4{
const int maxn=3e5;
int mul[maxn],inv[maxn],n;
inline int C(int n,int m){return 1ll*mul[n]*inv[m]%mod*inv[n-m]%mod;}
inline void pre(){
mul[0]=inv[0]=1;
for(int i=1;i<=n;i++) mul[i]=1ll*mul[i-1]*i%mod;
inv[n]=fpow(mul[n],mod-2);for(int i=n-1;i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
inline void main(){
n=262144;
pre();
printf("%d\n",n);
for(int i=0;i<=n;i++) printf("%d\n",C(n,i));
}
}

PS

后来思考了一下为什么输入把 131072 的一行组合数也全给了,根据二项式定理,输入给出的是 \((x+1)^n\),然后输出的 n 恰好是输入的两倍。所以实际上是让我们算 \((x+1)^{2n}\)。也就是做一遍多项式乘法。

会有人写这玩意吗,还是为了给没看出来是组合数的选手分?

Point 5

刚才切了第四个点的聚铑趁热打铁,瞬间就看出来了是每一项乘上了一个 \((-1)^i\) 。于是又切了。

当然,如果您想写多项式开根也可以。

因为和前面一个点比较像,就放在一起了。

namespace subtask4{
const int maxn=3e5;
int mul[maxn],inv[maxn],n;
inline int C(int n,int m){return 1ll*mul[n]*inv[m]%mod*inv[n-m]%mod;}
inline void pre(){
mul[0]=inv[0]=1;
for(int i=1;i<=n;i++) mul[i]=1ll*mul[i-1]*i%mod;
inv[n]=fpow(mul[n],mod-2);for(int i=n-1;i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
inline void main2(){
n=131072;
pre();
printf("%d\n",n);
for(int i=0;i<=n;i++) printf("%d\n",i&1?mod-C(n,i):C(n,i));
}
}

Point 6

刚才那位聚铑乘胜追击,观察了一下输入输出的项数,发现输出刚好是输入的 \(\frac{1}{3}\) 。

什么东西能减少项数,而且刚好减到 \(\frac{1}{3}\)?

只有聚铑知道答案。他一眼就看出来这似乎是一个多项式三次剩余,然后确实是对的。

然而珂爱似乎有更好的方法,因为这个 \(5e5\) 的数据范围,还是用的多项式快速幂真的太勉强了,加了快读快输开优化才能过。用珂爱的方法或者多项式三次方根或许能更好(更短)地通过此题。

namespace subtask6{
const int maxn=533000<<2,mod=104857601,g=3,gi=104857602/3,n=177147,p=63776689;
struct NTT{
int r[maxn],lim;
inline void getr(int li){
lim=li;
for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)*(lim>>1));
}
inline void operator () (int *a,int type) const {
for(int i=0;i<lim;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int mid=1;mid<lim;mid<<=1){
int rt=fpow(type==1?g:gi,(mod-1)/(mid<<1));
for(int r=mid<<1,j=0;j<lim;j+=r){
int p=1;
for(int k=0;k<mid;k++,p=1ll*p*rt%mod){
int x=a[j+k],y=1ll*p*a[j+k+mid]%mod;
a[j+k]=(x+y)%mod,a[j+k+mid]=(x-y+mod)%mod;
}
}
}
if(type==-1) for(int p=fpow(lim,mod-2),i=0;i<lim;i++) a[i]=1ll*a[i]*p%mod;
}
}ntt;
void inv(const int *a,int *ans,int n){
if(n==1) return ans[0]=fpow(a[0],mod-2),ans[1]=0,void();
static int res[maxn];
inv(a,ans,n>>1);
int lim=n<<1;
ntt.getr(lim);
for(int i=0;i<n;i++) res[i]=a[i];
for(int i=n;i<lim;i++) res[i]=ans[i]=0;
ntt(res,1),ntt(ans,1);
for(int i=0;i<lim;i++) ans[i]=ans[i]*(2-1ll*ans[i]*res[i]%mod+mod)%mod;
ntt(ans,-1);
for(int i=n;i<lim;i++) ans[i]=0;
}
inline void deri(const int *a,int *ans,int n){for(int i=1;i<n;i++) ans[i-1]=1ll*a[i]*i%mod;ans[n-1]=0;}
inline void inte(const int *a,int *ans,int n){for(int i=1;i<n;i++) ans[i]=1ll*a[i-1]*fpow(i,mod-2)%mod;ans[0]=0;}
inline void ln(const int *a,int *ans,int n){
static int res[maxn];
deri(a,res,n);
inv(a,ans,n);
int lim=n<<1;
ntt.getr(lim);
ntt(res,1),ntt(ans,1);
for(int i=0;i<lim;i++) res[i]=1ll*res[i]*ans[i]%mod,ans[i]=0;
ntt(res,-1);
inte(res,ans,n);
for(int i=0;i<lim;i++) res[i]=0;
}
void exp(const int *a,int *ans,int n){
if(n==1) return ans[0]=1,ans[1]=0,void();
static int res[maxn];
exp(a,ans,n>>1);
ln(ans,res,n);
int lim=n<<1;
ntt.getr(lim);
res[0]=(1+a[0]-res[0]+mod)%mod;
for(int i=1;i<n;i++) res[i]=(a[i]-res[i]+mod)%mod;
ntt(ans,1),ntt(res,1);
for(int i=0;i<lim;i++) ans[i]=1ll*ans[i]*res[i]%mod,res[i]=0;
ntt(ans,-1);
for(int i=n;i<lim;i++) ans[i]=0;
}
inline void fpow(int const *a,int *ans,int k,int n){
static int f[maxn],g[maxn];
for(int i=0;i<n;i++)g[i]=f[i]=ans[i]=0;
int d=0;
while(!a[d]&&d<n) ++d;
int u=::fpow(a[d],mod-2),v=22131490;
for(int i=0;i<n-d;i++)g[i]=1ll*a[i+d]*u%mod;
for(int i=n-d;i<n;i++)g[i]=0;
ln(g,f,n);
for(int i=0;i<n;i++)f[i]=1ll*f[i]*k%mod;
exp(f,ans,n);
d*=k;
for(int i=n-1;i>=d;i--)ans[i]=1ll*ans[i-d]*v%mod;
for(int i=0;i<d;i++)ans[i]=0;
}
int a[maxn],ans[maxn];
inline void main(){
for(int i=0;i<=n;i++) a[i]=read();
fpow(a,ans,::fpow(3,mod-2),1<<18);
out(n);
for(int i=0;i<=n;i++) out(ans[i]);
}
}

Point 2

终于要直面 01 串了。(由第一个点就可以知道我 01 串相关有多菜)

首先,一位聚铑通过观察文件大小发现字符个数恰好是斐波那契数列的第 33 项。

发现除了前三项,后面几项都符合斐波那契串。而一个斐波那契串内确实有这样的规律。

写了一下,发现是对的。

顺便模一下这位聚铑写得真可爱。

namespace subtask2{
string s[2]={"0","1"};
inline void main(){
for(int i=2;i<33;i++) s[i&1]=s[i&1]+s[i&1^1];
puts(s[0].c_str());
}
}

Point 3

这个点是最艰难的点了。

使劲找规律,先发现字符个数是 \(3^{12}+11\) ,然后思考有什么规律。

除去第一个 0,每 12 个数分开,看起来好像是三进制数每次 +1 再 +2 。

往后看了看,什么玩意

经过艰苦的奋斗,最终还是没找出来,于是去膜拜的珂爱的题解。感觉就是个找规律。因为是抄别人的,所以写出来也没啥意思。贴一下别人的代码。

namespace subtask3{
using namespace std;
void main()
{
unordered_set<string>st;
string s="000000000001",output="";
while(1){
output+=s[0];
st.insert(s);
s+=s[0];
s.erase(0,1);
while(st.count(s)&&s!="000000000000"){
++s[11];
for(int i=11;~i&&s[i]=='3';--i){
s[i]='0';
if(i)++s[i-1];
}
}
if(s=="000000000000")break;
}
cout<<0<<output<<"00000000000\n";
}
}

代码

都在上面了。贴一下我的主函数(包括第十个点的特判)和用到的全局函数和变量。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cmath>
#include<vector>
#include<string>
#include<unordered_set>
using namespace std;
inline int read(){
int w=0,x=0;char c=getchar();
while(!isdigit(c))w|=c=='-',c=getchar();
while(isdigit(c))x=x*10+(c^48),c=getchar();
return w?-x:x;
}
const int mod=104857601;
char O_[999999],*OU=O_,*OV=OU+999991,OS[21],*OT=OS;
#define F fwrite(O_,1,OU-O_,stdout)
#define O(x) (*(OU=(OU==OV?(F,O_):OU))++=(x))
void out(int x){for(;*OT++=x%10+48,x/=10;);for(;OT!=OS;O(*--OT));O(10);}
inline int fpow(int a,int b){int ans=1;for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod;return ans;}
int n;
//------------------------------------------------------------
signed main(){
char s[10];
scanf("%s",s);
if(strcmp(s,"Maybe")==0) return puts("Your program should output itself here.\nSounds very difficult, yeah?\nAnyway, good luck!"),0;
n=atoi(s);
if(n==22)subtask1::main();
if(n==33)subtask2::main();
if(n==12)subtask3::main();
if(n==531441)subtask6::main();
if(n==131072)subtask4::main();
if(n==262144)subtask4::main2();
if(n==100000){
int m=read();
if(m==100000) subtask7::main(n,m);
else subtask8::main();
}else if(n==50000) subtask9::main();
return F,0;
}

P5042 丢失的题面的更多相关文章

  1. SCOI 2019 划水记

    (此处不应有目录,爆零的过程得慢慢看) 鸽子来更新游记了 orz UESTC. Day -1 两场傻逼信心考试都没AK. 第一场真的气,一个边界觉得是i - 1,然后不知道为啥改成了i,挂了6个点,然 ...

  2. HEOI 十二省联考退役记

    Day -1 简要的说了些注意事项 一整天都在刷树套树的水题 退役的感觉近了 Day 0 早上收拾好东西去了火车站之后 火车站居然还没有开门 等了半天 我们是从衡水到德州再到秦皇岛 到了德州之后 去车 ...

  3. HEOI2019游记(退役记)

    少了回程铁路相关信息,有空补 AFO 辣鸡蒟蒻ghj1222顺利地退役了 由于没带手机拍照片,本次坐动车不写运转记录,下次去CTS/APIO应该是坐普速车,应该能带手机拍照,应该会写运转记录 Day ...

  4. 关于"丢失的牛"这个题的教学反思

    某天上课讲到这样一个题:丢失的牛1~n,乱序排列,告诉从第二个位置到最后一个位置, 每个位置的前面的数字中比它小的数的个数,求每个位置的数字是多少N<=8000 FormatInput第一行给出 ...

  5. [LeetCode] Missing Number 丢失的数字

    Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...

  6. 递归一题总结(OJ P1117倒牛奶)

    题目:                    农民约翰有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数,最初,A和B桶都是空的,而C桶是装满牛奶的.有时,约翰把牛奶从一个桶倒到另 ...

  7. jsp考试的错题

    (选择一项) A: B: C: D: 正确答案是 A,首先,session的出现确实是为了解决HTTP无法保持客户状态的特点:因此A选项正确:用户信息也是客户状态的一部分,所以由A可以看出B的说法就不 ...

  8. jsp前三章测试改错题

      (选择一项) A: B: C: D: 正确答案是 B ,B/S架构并不是C/S架构的替代品,有些程序例如大型的网络游戏一般使用的是C/S架构. (选择多项) A: B: C: D: 正确答案是 A ...

  9. 玉伯的一道课后题题解(关于 IEEE 754 双精度浮点型精度损失)

    前文 的最后给出了玉伯的一道课后题,今天我们来讲讲这题的思路. 题目是这样的: Number.MAX_VALUE + 1 == Number.MAX_VALUE; Number.MAX_VALUE + ...

随机推荐

  1. 查找文件与cron计划任务

    查找文件 • 根据预设的条件递归查找对应的文件 find [目录] [条件1] [-a|-o] [条件2] ... -type  类型(f文件.d目录.l快捷方式) -name  "文档名称 ...

  2. 设置NX欢迎界面

    环境变量 变量名:UGII_WELCOME_PAGE 变量值:http://www.baidu.com/

  3. spring boot 并发请求,其他系统接口,丢失request的header信息【多线程、线程池、@Async 】

    场景:一次迭代在灰度环境发版时,测试反馈说我开发的那个功能,查询接口有部分字段数据是空的,后续排查日志,发现日志如下: feign.RetryableException: cannot retry d ...

  4. Docker启动PostgreSQL时创建多个数据库

    1 前言 在文章<Docker启动PostgreSQL并推荐几款连接工具>中我们介绍如何通过Docker来启动PostgreSQL,但只有一个数据库,如果想要创建多个数据库在同一个Dock ...

  5. POJ 1572 Automatic Editing 字符串替换,replace就够了

    题意不难理解,但是一开始还是没有看清楚题目.Replace the first occurrence of the find string within the text by the replace ...

  6. CentOS 8 按tab键不能自动补全问题解决方案

    CentOS中按tab键不能自动补全问题解决办法 检查一下系统有没有安装bash-completion包 [root@Sonarqube ~]# rpm -lq bash-completion yum ...

  7. Java Set HashSet

    import java.util.HashSet; import java.util.Set; /** Set存储特点:数据无序.不可重复 Set接口的实现类: HashSet:Set接口的主要实现类 ...

  8. [Kick Start] 2021 Round B

    题目:Kick Start 2021 Round-B . Increasing Substring 输出字符串中每个字符的最长 Increasing Substring 的长度,非常简单的动态规划问题 ...

  9. Mysql:报错message from server: "Too many connections"(连接太多)

    报错信息 Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source re ...

  10. linux中的vim用法

    p.p1 { margin: 0; font: 16px ".PingFang SC"; color: rgba(53, 53, 53, 1) } p.p2 { margin: 0 ...