P5042 丢失的题面
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
01101001
和 011010011001
。做了一下,发现是对的。
然后观察文件大小发现输出的字符串长度是 \(2^{22}\) 。没细想,写完就过了。
但是为什么是 \(2^{22}\) 呢?
我回头看了一眼,发现输出好像是初始一个 0 字符,每次操作将当前串取反拼接到后面,做 22 次的结果……(鬼知道我当初为啥直接就想每 4 个分组)
然后又看了下 OEIS,发现这个输出本身就是一个数列:A010060。这个序列还有个名字叫做
在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 丢失的题面的更多相关文章
- SCOI 2019 划水记
(此处不应有目录,爆零的过程得慢慢看) 鸽子来更新游记了 orz UESTC. Day -1 两场傻逼信心考试都没AK. 第一场真的气,一个边界觉得是i - 1,然后不知道为啥改成了i,挂了6个点,然 ...
- HEOI 十二省联考退役记
Day -1 简要的说了些注意事项 一整天都在刷树套树的水题 退役的感觉近了 Day 0 早上收拾好东西去了火车站之后 火车站居然还没有开门 等了半天 我们是从衡水到德州再到秦皇岛 到了德州之后 去车 ...
- HEOI2019游记(退役记)
少了回程铁路相关信息,有空补 AFO 辣鸡蒟蒻ghj1222顺利地退役了 由于没带手机拍照片,本次坐动车不写运转记录,下次去CTS/APIO应该是坐普速车,应该能带手机拍照,应该会写运转记录 Day ...
- 关于"丢失的牛"这个题的教学反思
某天上课讲到这样一个题:丢失的牛1~n,乱序排列,告诉从第二个位置到最后一个位置, 每个位置的前面的数字中比它小的数的个数,求每个位置的数字是多少N<=8000 FormatInput第一行给出 ...
- [LeetCode] Missing Number 丢失的数字
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...
- 递归一题总结(OJ P1117倒牛奶)
题目: 农民约翰有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数,最初,A和B桶都是空的,而C桶是装满牛奶的.有时,约翰把牛奶从一个桶倒到另 ...
- jsp考试的错题
(选择一项) A: B: C: D: 正确答案是 A,首先,session的出现确实是为了解决HTTP无法保持客户状态的特点:因此A选项正确:用户信息也是客户状态的一部分,所以由A可以看出B的说法就不 ...
- jsp前三章测试改错题
(选择一项) A: B: C: D: 正确答案是 B ,B/S架构并不是C/S架构的替代品,有些程序例如大型的网络游戏一般使用的是C/S架构. (选择多项) A: B: C: D: 正确答案是 A ...
- 玉伯的一道课后题题解(关于 IEEE 754 双精度浮点型精度损失)
前文 的最后给出了玉伯的一道课后题,今天我们来讲讲这题的思路. 题目是这样的: Number.MAX_VALUE + 1 == Number.MAX_VALUE; Number.MAX_VALUE + ...
随机推荐
- spring IOC DI AOP MVC 事务, mybatis 源码解读
demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...
- 【Java面试真题】剑指Offer53.2——0~n-1中缺失的数字(异或、二分两种解法)
[Java实现]剑指Offer53.2--0~n-1中缺失的数字:面试真题,两种思路分享 前面有另一道面试题[Java实现]剑指offer53.1--在排序数组中查找数字(LeetCode34:在排序 ...
- Bind DNS服务——转发与区域记录更新
Linux基础服务--Bind DNS服务 Part4 转发与区域记录更新 一个DNS服务器不可能保存所有的区域记录,所以我们一般都会将其他的区域纪录转发到其他的服务器上进行解析. Bind9提供了全 ...
- 解决git冲突
多个开发者同时操作git中的同一个文件,第一个人在commit和push的时候是可以正常提交的,而之后的开发者执行pull,就会报冲突异常conflict. 解决方案: 全部采用当前更改 之后再去gi ...
- Spring Boot WebFlux-导读
背景 大家都知道,Spring Framework 是 Java/Spring 应用程序跨平台开发框架,也是 Java EE(Java Enterprise Edition) 轻量级框架,其 Spri ...
- 小白学k8s(9)-gitlab-runner实现go项目的自动化发布
gitlab构建CI/CD 准备 docker部署gitlab 使用二进制部署gitlab-runner gitlab-runner注册 配置Variables 简单先来个测试 开始构建 遇到的报错 ...
- Siamese network总结
前言: 本文介绍了Siamese (连体)网络的主要特点.训练和测试Siamese网络的步骤.Siamese网络的应用场合.Siamese网络的优缺点.为什么Siamese被称为One-shot分类 ...
- 精尽Spring Boot源码分析 - 序言
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
- CentOS7详细安装教程(图文)
CentOS7安装过程:(图文详解) 为了做实验,装台Linux的虚拟机,手上有这个7的ISO文件就懒得去下载8的了. 0X01.虚拟机配置 0X02.CentOS7系统配置安装 分别创建/boot区 ...
- 温故知新,基于Nexus3和Docker搭建私有Docker Mirrors镜像库
前言 接着上一篇文章关于基于Nexus3和Docker搭建私有Nuget服务的探索,我们可以进一步利用Nexus3来创建一个私有的Docker镜像库满足内部需求. 仓库类型 hosted: 本地存储, ...