题目来源
题目大意
构造一棵树,使直径数量为 k k k
输出构造出的树的节点数量和每条边的端点与权值。
比赛情况
比赛时,我想到正解并实现出来。
但是输出的时候把所有的节点数输成边数了,这样的会使节点数都少 1 1 1。
后面也没有管理好时间没有去检查这一道题,导致直接 W a − 0 Wa-0 Wa−0, 100 100 100分都付之东流了。
以后做题以后用样例检查时不能仅仅只检查局部的正确性,整个答案是否合法也需检查判断。
还有比赛时不能浪费一分一秒,要是把放空那10分钟拿来检查代码,那么就不会发生这样的情况。
详细思路
对于边等长的菊花图,边的数量 a a a,这样的图的直径数量是 a ( a − 1 ) 2 \frac{a(a-1)}{2} 2a(a−1)
假若菊花图中有一条边比其它边 长的话,边的数量 a a a,那么直径数量是 a − 1 a-1 a−1
这样构图能够弄出每一种直径数量,但是这样构图的节点数远远大于题目限制数 5000 5000 5000
那假若不仅仅有一条比较长边呢?那么这几条相同的边会互相形成更长的直径。
但也是能避免较长边互相形成更长的直径,只要较长边与短边中间加一条非常大的边即可(如下图)
这样可以将图的直径数处理成两个部分的边数乘积,大幅度减少了图的节点数量
即使这样优化,遇到质数的时候,是会比第一种情况更劣
那么是否可以再分为多个部分呢?
假若分为3个部分,每个部分里的边全是相同的,不同部分的边是不同大小,那么只有最大和次大部分能产生贡献
当每个部分的边的大小相同的话,此时每两个部分间能互相产生贡献(如下图)
令每部分里的边的数量分别为 a , b , c a,b,c a,b,c
直径数量即为 ( a b + b c + c a ) (ab+bc+ca) (ab+bc+ca)
当直径数量比较大时,一定能够用 ( a b + b c + c a ) (ab+bc+ca) (ab+bc+ca)表示
对于求 a , b , c a,b,c a,b,c可以从 直径数量 \sqrt{直径数量} 直径数量开始往 1 1 1枚举 a , b a,b a,b,再用 ( 直径数量 − a b ) m o d ( a + b ) = = 0 (直径数量-ab)mod(a+b)==0 (直径数量−ab)mod(a+b)==0来判断合法性,合法时 c = 直径数量 − a b a + b c=\frac{直径数量-ab}{a+b} c=a+b直径数量−ab
若不能用 ( a b + b c + c a ) (ab+bc+ca) (ab+bc+ca)表示,那就用第一种方法和第二种方法解决
心声
如果你仔细观察会发现,我这篇博客里所有的较大边(包括代码里的)
因为我想祝愿你,从今以后你做所有的题目都能拿到 100 100 100%的分数
具体实现
#include<cstdio>
#include<cmath>
using namespace std;
long long n,m,k=0,w,A1,A2,A3;
void Dfs(){
for(int i=w;i>=1;i--){
for(int j=w;j>=1;j--){
if((n-i*j)%(i+j)==0){A1=i;A2=j;A3=(n-i*j)/(i+j);return;}
}
}
return;
}
int main(){
freopen("diameter.in","r",stdin);
freopen("diameter.out","w",stdout);
scanf("%lld",&n);w=sqrt(n);
if(n==1){printf("2\n1 2 1");return 0;}
if(n==2){printf("4\n1 2 2\n1 3 1\n1 4 1\n");return 0;}
Dfs();
if(A1==0&&A2==0&&A3==0){
m=2;
printf("%lld\n1 2 100\n",n+2);
for(long long i=1;i<=n;i++)printf("1 %lld 1\n",i+m);
}
else if(A3==0){
m=2;
printf("%lld\n1 2 100\n",A1+A2+2);
for(int i=1;i<=A1;i++)m++,printf("1 %lld 1\n",m);
for(int i=1;i<=A2;i++)m++,printf("2 %lld 1\n",m);
}
else{
m=4;
printf("%lld\n1 2 100\n1 3 100\n1 4 100\n",A1+A2+A3+4);
for(int i=1;i<=A1;i++)m++,printf("2 %lld 1\n",m);
for(int i=1;i<=A2;i++)m++,printf("3 %lld 1\n",m);
for(int i=1;i<=A3;i++)m++,printf("4 %lld 1\n",m);
}
}