把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5246】[集训队互测2016] 消失的源代码(有趣的提答题)

点此看题面

大致题意:\(10\)\(Subtask\),每个\(Subtask\)给你一个不完美的可执行程序和一个输入文件,让你求出输出文件。

子任务\(1\)

简单分析,可以发现对于每个输入的字符,你要输出一个与其对应的字符。

则可通过打表得到每个字符所对应的字符。

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
using namespace std;
int v[27]={0,'y','f','r','b','k','g','i','m','u','j','v','p','h','a','t','d','s','n','e','l','o','z','c','x','w','q'};//打得的表
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        char c,*A,*B,FI[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        I void reads(string& x) {x="";W(isspace(c=tc()));W(x+=c,!isspace(c=tc())&&~c);}
}F;
int main()
{
	freopen("input1.txt","r",stdin),freopen("output1.txt","w",stdout);
	RI Tpos,Ttot,i,len;Reg char c;Reg string s;
	F.read(Tpos,Ttot);W(Ttot--)
	{
		for(F.reads(s),len=s.length(),i=0;i^len;++i) putchar(v[s[i]&31]);//输出对应字符
		putchar('\n');//换行
	}return 0;
}

子任务\(2\)

先打表得到\(n=1\sim5\)的输出结果分别为\(2030,8082,18166,32282,50430\)

考虑其每次增加的值分别为\(6052,10084,14116,18148\),而增加的值所相差的值都为\(4032\)

设第\(i\)个数为\(f_i\),则不难得到:

\[f_i=2030+6052(i-1)+4032\frac{(i-2)(i-1)}2=2016i^2+4i+10 \]

貌似做完了?

等等,这种式子肯定需要取模!

我们继续打表,可以发现在\(n=10\)时,\(ans=201650\),但\(n=11\)时,\(ans\)就变成了\(10657\)

\(f_{11}=243990\),与\(10657\)刚好相差\(233333\)

所以模数必为\(233333\)

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define X 233333
using namespace std;
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C,stdout),C=0;}
}F;
int main()
{
	freopen("input2.txt","r",stdin),freopen("output2.txt","w",stdout);
	RI Tpos,Ttot,x;F.read(Tpos,Ttot);W(Ttot--) F.read(x),F.writeln((1LL*2016*x%X*x%X+4LL*x+10)%X);//计算并输出答案
	return F.clear(),0;
}

子任务\(3\)

同样是考虑打表,发现这次得到的式子增长速度特别慢。

\(hl666\)神仙一起想了半天没想出来,最后放到\(OEIS\)上,发现是这样一个式子:

\[\lfloor\sqrt{\frac i\pi}\rfloor \]

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
using namespace std;
const double Pi=acos(-1);
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C,stdout),C=0;}
}F;
int main()
{
	freopen("input3.txt","r",stdin),freopen("output3.txt","w",stdout);
	RI Tpos,Ttot,x;F.read(Tpos,Ttot);W(Ttot--) F.read(x),F.writeln((int)floor(sqrt(x/Pi)));//计算并输出答案
	return F.clear(),0;
}

子任务\(4\)

观察数据形式,易得:输入第一行两个数数\(n,m\),分别表示节点个数和边数。其后\(m\)行,每行两个数表示一条边。

观察样例,可发现答案就是各连通块大小的平方和

可以用并查集维护连通性,最后再统计答案即可。

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define LL long long
using namespace std;
int n,m;
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C,stdout),C=0;}
}F;
class UnionFindSet//并查集
{
	private:
		static const int SZ=N;int fa[SZ+5],cnt[SZ+5];
		I int getfa(CI x) {return fa[x]^x?fa[x]=getfa(fa[x]):x;}//找祖先
	public:
		I void Init(CI n) {for(RI i=1;i<=n;++i) cnt[fa[i]=i]=0;}//初始化
		I void Union(RI x,RI y)	{(x=getfa(x))^(y=getfa(y))&&(fa[y]=x);}//合并两个节点
		I LL Query(CI n)//询问
		{
			RI i;Reg LL ans=0;for(i=1;i<=n;++i) ++cnt[getfa(i)];//统计
			for(i=1;i<=n;++i) ans+=1LL*cnt[i]*cnt[i];return ans;//计算答案
		}
}U;
int main()
{
	freopen("input4.txt","r",stdin),freopen("output4.txt","w",stdout);
	RI Tpos,Ttot,i,x,y;F.read(Tpos,Ttot);W(Ttot--) 
	{
		for(F.read(n,m),U.Init(n),i=1;i<=m;++i) F.read(x,y),U.Union(x,y);//对每条边依次合并连通块
		F.writeln(U.Query(n));//输出答案
	}return F.clear(),0;
}

子任务\(5\)

观察数据形式,易得:输入第一行两个数\(n,Q\),分别表示节点个数和询问个数。其后\(n-1\)行,每行两个数表示一条边(可见这是一棵树)。再然后是\(Q\)行,每行两个数,表示一个询问。

手造小数据容易得出,每次询问的是树上两点间的距离,最后要输出答案的异或和。

这用树上倍增即可。

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define LogN 17
#define LL long long
#define swap(x,y) (x^=y^=x^=y)
#define add(x,y,v) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].val=v)
using namespace std;
int n,m,ee,lnk[N+5];struct edge {int to,nxt,val;}e[N<<1];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C,stdout),C=0;}
        #undef D
}F;
class TreeSolver//树上倍增
{
	private:
		int D[N+5],F[N+5][LogN+5];LL Dis[N+5][LogN+5];
	public:
		I void dfs(CI x,CI lst)//DFS预处理
		{
			RI i;for(i=1;i<=LogN;++i) F[x][i]=F[F[x][i-1]][i-1],Dis[x][i]=Dis[x][i-1]+Dis[F[x][i-1]][i-1];//求出F数组和Dis数组
			for(i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&(D[e[i].to]=D[F[e[i].to][0]=x]+1,Dis[e[i].to][0]=e[i].val,dfs(e[i].to,x),0);//遍历子树
		}
		I LL GetDis(RI x,RI y)//求出树上两点间的距离
		{
			RI i;Reg LL t=0;for(D[x]<D[y]&&swap(x,y),i=0;D[x]^D[y];++i) (D[x]^D[y])&(1<<i)&&(t+=Dis[x][i],x=F[x][i]);
			if(!(x^y)) return t;for(i=LogN;~i;--i) F[x][i]^F[y][i]&&(t+=Dis[x][i]+Dis[y][i],x=F[x][i],y=F[y][i]);
			return t+Dis[x][0]+Dis[y][0];
		}
}T;
int main()
{
	freopen("input5.txt","r",stdin),freopen("output5.txt","w",stdout);
	RI Tpos,Ttot,i,x,y,v;Reg LL ans;F.read(Tpos,Ttot);W(Ttot--)
	{
		for(F.read(n,m),ee=0,i=1;i<=n;++i) lnk[i]=0;for(i=1;i^n;++i) F.read(x,y,v),add(x,y,v),add(y,x,v);//清空数组+读入+连边
		for(T.dfs(1,0),ans=0,i=1;i<=m;++i) F.read(x,y),ans^=T.GetDis(x,y);F.writeln(ans);//求解答案
	}return F.clear(),0;
}

子任务\(6\)

与子任务\(5\)差不多,只不过询问的变成了树上两点间的最小边权。

我们可以通过询问同一个点间的最小边权,来求出其\(ans\)初始化为\(1987654321\)

然后同样用树上倍增即可。

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define LogN 17
#define min(x,y) ((x)<(y)?(x):(y))
#define Gmin(x,y) ((x)>(y)&&(x=(y)))
#define swap(x,y) (x^=y^=x^=y)
#define add(x,y,v) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].val=v)
using namespace std;
int n,m,ee,lnk[N+5];struct edge {int to,nxt,val;}e[N<<1];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C,stdout),C=0;}
        #undef D
}F;
class TreeSolver//树上倍增
{
	private:
		#define P 1987654321//ans初始值
		int D[N+5],F[N+5][LogN+5],M[N+5][LogN+5];
	public:
		I void dfs(CI x,CI lst)//DFS预处理
		{
			RI i;for(i=1;i<=LogN;++i) F[x][i]=F[F[x][i-1]][i-1],M[x][i]=min(M[x][i-1],M[F[x][i-1]][i-1]);//求出F数组和M数组
			for(i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&(D[e[i].to]=D[F[e[i].to][0]=x]+1,M[e[i].to][0]=e[i].val,dfs(e[i].to,x),0);//遍历子树
		}
		I int GetMin(RI x,RI y)//求出树上两点间的最小边权
		{
			RI i,t=P;for(D[x]<D[y]&&swap(x,y),i=0;D[x]^D[y];++i) (D[x]^D[y])&(1<<i)&&(Gmin(t,M[x][i]),x=F[x][i]);
			if(!(x^y)) return t;for(i=LogN;~i;--i) F[x][i]^F[y][i]&&(Gmin(t,M[x][i]),Gmin(t,M[y][i]),x=F[x][i],y=F[y][i]);
			return min(t,min(M[x][0],M[y][0]));
		}
}T;
int main()
{
	freopen("input6.txt","r",stdin),freopen("output6.txt","w",stdout);
	RI Tpos,Ttot,i,x,y,v,ans;F.read(Tpos,Ttot);W(Ttot--)
	{
		for(F.read(n,m),ee=0,i=1;i<=n;++i) lnk[i]=0;for(i=1;i^n;++i) F.read(x,y,v),add(x,y,v),add(y,x,v);//清空数组+读入+连边
		for(T.dfs(1,0),ans=0,i=1;i<=m;++i) F.read(x,y),ans^=T.GetMin(x,y);F.writeln(ans);//求解答案
	}return F.clear(),0;
}

子任务\(7\)

数据给你的是两个数\(n\)\(m\)

通过大量测试和猜测可得我们要求的式子为:

\[\sum_{i=1}^n\sum_{j=1}^mgcd(i,j) \]

观察\(input.txt\),可以发现除了一组\(100\ 1000\)的数据外,其余的数据都满足\(n=m\)

\(100\ 1000\)的数据我们完全可以暴力求解。

否则,我们将\(n=m\)代入得到:

\[\sum_{i=1}^n\sum_{j=1}^ngcd(i,j) \]

这应该是比较经典的式子,我们枚举\(gcd\)得:

\[\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac nd\rfloor}d[gcd(i,j)==1] \]

\(d\)提前得:

\[\sum_{d=1}^nd\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac nd\rfloor}[gcd(i,j)==1] \]

而后半部分可以运用\(\phi\)的定义转化,于是得到这样一个式子:

\[\sum_{d=1}^nd(2\sum_{i=1}^{\lfloor\frac nd\rfloor}\phi(i)-1) \]

\(n\)不大,可以直接线性筛筛出\(\phi\)的前缀和,然后枚举\(d\)求解即可。

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define LL long long
using namespace std;
int n,m;
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C,stdout),C=0;}
}F;
class BruteForceSolver//暴力求解n!=m的情况
{
	private:
		I int gcd(CI x,CI y) {return y?gcd(y,x%y):x;}//求解gcd
	public:
		I void Solve()
		{
			RI i,j;Reg LL ans=0;
			for(i=1;i<=n;++i) for(j=1;j<=m;++j) ans+=gcd(i,j);//大暴力统计答案
			F.writeln(ans);//输出答案
		}
}B;
class MathSolver//用数学方法求解n=m的情况
{
	private:
		class LineSiever//线性筛筛出φ的前缀和
		{
			private:
				static const int SZ=1000000;int Pcnt,P[SZ+5],phi[SZ+5];
			public:
				LL Sphi[SZ+5];
				I LineSiever()
				{
					RI i,j;for(phi[1]=1,i=2;i<=SZ;++i) for(!P[i]&&(phi[P[++Pcnt]=i]=i-1),j=1;1LL*i*P[j]<=SZ;++j)
						if(P[i*P[j]]=1,i%P[j]) phi[i*P[j]]=phi[i]*(P[j]-1);else {phi[i*P[j]]=phi[i]*P[j];break;}
					for(i=1;i<=SZ;++i) Sphi[i]=Sphi[i-1]+phi[i];//统计前缀和
				}
		}S;
	public:
		I void Solve()
		{
			RI i;Reg LL ans=0;
			for(i=1;i<=n;++i) ans+=1LL*i*(2*S.Sphi[n/i]-1);//统计答案
			F.writeln(ans);//输出答案
		}
}M;
int main()
{
	freopen("input7.txt","r",stdin),freopen("output7.txt","w",stdout);
	RI Tpos,Ttot;F.read(Tpos,Ttot);W(Ttot--) F.read(n,m),n^m?B.Solve():M.Solve();//分情况选择解决方案
	return F.clear(),0;
}

子任务\(8\)

手造几组小数据,可发现这题求的是给定序列本质不同的子串个数。

后缀数组裸题,答案就是:

\[\frac{n(n+1)}2-\sum_{i=1}^nHeight_i \]

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000000
#define LL long long
using namespace std;
int n,a[N+5];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) (C^FS?FO[C++]=c:(fwrite(FO,1,C,stdout),FO[(C=0)++]=c))
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Tp I void writeln(Con Ty& x) {write(x),pc('\n');}
        I void clear() {fwrite(FO,1,C,stdout),C=0;}
}F;
class SuffixArray//后缀数组
{
	private:
		static const int SZ=N;int n,SA[SZ+5],H[SZ+5],R[SZ+5],P[SZ+5],T[SZ+5];
		I void Rsort(CI S)//基数排序
		{
			RI i;for(i=0;i<=S;++i) T[i]=0;for(i=1;i<=n;++i) ++T[R[i]];
			for(i=1;i<=S;++i) T[i]+=T[i-1];for(i=n;i;--i) SA[T[R[P[i]]]--]=P[i];
		}
		I void GetSA(int* s)//求出SA数组
		{
			RI i,k,S=N,t=0;for(i=1;i<=n;++i) R[P[i]=i]=s[i];
			for(Rsort(S),k=1;t^n;k<<=1)
			{
				for(S=t,t=0,i=1;i<=k;++i) P[++t]=n-k+i;	
				for(i=1;i<=n;++i) SA[i]>k&&(P[++t]=SA[i]-k);
				for(Rsort(S),i=1;i<=n;++i) P[i]=R[i];
				for(R[SA[1]]=t=1,i=2;i<=n;++i) R[SA[i]]=(P[SA[i-1]]^P[SA[i]]||P[SA[i-1]+k]^P[SA[i]+k])?++t:t;
			}
		}
		I void GetHeight(int* s)//求出Height数组
		{
			RI i,j,k=0;for(i=1;i<=n;++i) R[SA[i]]=i;
			for(i=1;i<=n;++i)
			{
				if(k&&--k,!(R[i]^1)) continue;j=SA[R[i]-1];
				W(i+k<=n&&j+k<=n&&!(s[i+k]^s[j+k])) ++k;H[R[i]]=k;
			}
		}
	public:
		I void Init(CI len,int* s) {n=len,GetSA(s),GetHeight(s);}//初始化
		I LL GetAns() {Reg LL t=1LL*n*(n+1)>>1;for(RI i=1;i<=n;++i) t-=H[i];return t;}//计算答案
}S;
int main()
{
	freopen("input8.txt","r",stdin),freopen("output8.txt","w",stdout);
	RI Tpos,Ttot,i;F.read(Tpos,Ttot);W(Ttot--) 
	{
		for(F.read(n),i=1;i<=n;++i) F.read(a[i]);//读入
		S.Init(n,a),F.writeln(S.GetAns());//求解
	}return F.clear(),0;
}

子任务\(9\)

同样是通过造小数据,可发现这题就是求平面最近点对

计算几何做即可。

代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000000
#define DB double
#define INF 1e9
#define dis(A,B) sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y))
#define min(x,y) ((x)<(y)?(x):(y))
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
int n,s[N+5];
struct Point//存储点
{
	DB x,y;
	I friend bool operator < (Con Point& x,Con Point& y) {return x.x==y.x?x.y<y.y:x.x<y.x;}//按x坐标排序
}p[N+5];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        char c,*A,*B,FI[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}F;
I bool cmp(CI x,CI y) {return p[x].y<p[y].y;}//按y坐标排序
I double Solve(CI l,CI r)//分治
{
	if(!(l^r)) return INF;if(r-l==1) return dis(p[l],p[r]);RI i,j,t=0,mid=l+r>>1;//判断边界情况
	Reg DB d1=Solve(l,mid),d2=Solve(mid+1,r),d3,d=min(d1,d2);//分治两个区间,求答案
	for(i=l;i<=r;++i) fabs(p[mid].x-p[i].x)<=d&&(s[++t]=i);//将可能符合条件的点的编号加入数组
	for(sort(s+1,s+t+1,cmp),i=1;i<=t;++i) for(j=i+1;j<=t&&p[s[j]].y-p[s[i]].y<=d;++j) d3=dis(p[s[i]],p[s[j]]),Gmin(d,d3);//排序后用可能符合条件的点对更新答案
	return d;//返回答案
}
int main()
{
	freopen("input9.txt","r",stdin),freopen("output9.txt","w",stdout);
	RI Tpos,Ttot,i,x,y;F.read(Tpos,Ttot);W(Ttot--) 
	{
		for(F.read(n),i=1;i<=n;++i) F.read(x,y),p[i].x=x,p[i].y=y;//读入数据
		sort(p+1,p+n+1),printf("%.3lf\n",Solve(1,n));//排序,然后分治输出答案
	}return 0;
}

子任务\(10\)

最神奇的一个子任务。

这题的程序连第一个输入都会输出“\(invalid\ input!\)

这时我便大胆猜想:这题就是输出\(10\)个“\(invalid\ input!\)

结果真过了。

关于洛谷题目的吐槽

以上便是这道题的全部解法,这在\(UOJ\)上是可以轻松过的。

但可惜洛谷上交不了这么大的文件,结果只能写成代码,将第一个子任务直接搞,其余子任务打表输出答案。

\(AC\)代码如下:

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
using namespace std;
class Subtask1Solver//处理第一个子任务
{
	private:
		int v[27]={0,'y','f','r','b','k','g','i','m','u','j','v','p','h','a','t','d','s','n','e','l','o','z','c','x','w','q'};
	public:
		I void Solve()
		{
			RI Ttot,i,len;Reg char c;Reg string s;scanf("%d",&Ttot);W(Ttot--)
			{
				for(cin>>s,len=s.length(),i=0;i^len;++i) putchar(v[s[i]&31]);
				putchar('\n');
			}
		}
}S;
//以下为打表代码
I void Print2() {puts("106491\n189151\n42510\n93772\n32326\n6890\n94677\n168190\n66840\n93722");}
I void Print3() {puts("126\n126\n178\n252\n252\n626\n1982\n6268\n14567\n17730\n");}
I void Print4() {puts("68\n132\n171\n138\n225\n6592\n621318\n64147302\n1588039630\n6348298844");}
I void Print5() {puts("531842264\n3996089551\n1217487770\n13846806112\n2258552000\n12273908750\n31068785149\n453868136017\n7989258282893\n3571890382468");}
I void Print6() {puts("1159833908\n380176501\n1615846343\n1005775280\n1900756444\n139818805\n2130798985\n1503185154\n433569593\n988651389");}
I void Print7() {puts("880\n31080\n325200\n4449880\n135637352\n584509280\n72434344904\n306591086320\n2055466926488\n8643257847824");}
I void Print8() {puts("51\n108\n153\n4929\n124260\n498810\n12491602\n49971923\n2739460784\n499996516402");}
I void Print9() {puts("2.236\n69.527\n8.944\n10.440\n10.198\n1.414\n57.489\n10.770\n5.000\n8.544");}
I void Print10() {for(RI i=1;i<=10;++i) puts("invalid input!");}
int main()
{
	RI Tpos;switch(scanf("%d",&Tpos),Tpos)
	{
		case 1:S.Solve();break;case 2:Print2();break;
		case 3:Print3();break;case 4:Print4();break;
		case 5:Print5();break;case 6:Print6();break;
		case 7:Print7();break;case 8:Print8();break;
		case 9:Print9();break;case 10:Print10();break;
	}return 0;
}
posted @ 2019-03-09 00:01  TheLostWeak  阅读(392)  评论(0编辑  收藏  举报