如何加强一道题目(详细揭秘)
加强一道题目是怎么回事呢?那么一道题目为什么会被加强,相信大家都很好奇。大家可能会感到很惊讶,一道题目为什么会被加强呢?但事实就是这样,小编也感到非常惊讶。
提交链接:https://www.luogu.com.cn/problem/U259119。
欢迎大家来自测!
本来打算补一补这道咕了巨久的题目,然后发现你谷讨论区有人指出这题能加强。
然后花了大概半天的时间补掉这题。
然后开始咕咕咕地加强。
写了一个很复杂的生成树的 Gen,然后询问写挂以为树建挂了调了巨久……
好消息是,这个板子可以用于很多生成树的情景。
实现了:
- \(f_p<p\) 的生成器。
- \(n^{n-2}\) 颗树中随机选择的生成器。
- 链、菊花、蒲公英的生成器。
- 对边进行随机重标号、随机打乱。
- 给边加随机权。
- 校验树的合法性。
是以
using Vtype = std::vector<int>;
using Etype = std::vector<std::pair<int,int> >;
using EVtype = std::vector<std::pair<std::pair<int,int>,int> >;
的形式存储的,欢迎大家在下次造树时使用!
Code
树为 \(0\) 标号,要改为 \(1\) 标号请调用 Addlabel(E,1);
。
#include "testlib.h"
using Vtype = std::vector<int>;
using Etype = std::vector<std::pair<int,int> >;
using EVtype = std::vector<std::pair<std::pair<int,int>,int> >;
void Relabel(Etype&Edge,bool op1=true,bool op2=false,random_t&rng=rnd){
int n=Edge.size()+1;
Vtype To(n);
for(int i=0;i<n;i++)
To[i]=i;
std::mt19937 r(rng.next(1u<<30));
shuffle(To.begin(),To.end(),r);
for(auto&e:Edge)
e.first=To[e.first],e.second=To[e.second];
if(op1)
shuffle(Edge.begin(),Edge.end(),r);
if(op2)for(auto&e:Edge)if(rng.next(2))
std::swap(e.first,e.second);
}
void Addlabel(Etype&Edge,int v){
for(auto&e:Edge)
e.first+=v,e.second+=v;
}
Etype RandTree1(int n,int t=0,random_t&rng=rnd){
Etype Edge;
for(int i=1;i<n;i++)
Edge.push_back({i,rng.wnext(i,t)});
return Edge;
}
Etype RandTree2(int n,int t=0,random_t&rng=rnd){
Etype Edge;
Vtype A(n-2),D(n,1),u;
for(int i=0;i<n-2;i++)D[A[i]=rng.wnext(n,t)]++;
int id=0;
for(int i=0;i<n;i++)if(D[i]==1){
int p=i;
do
{
if(id==n-2)break;
D[p]=-1;
int s=A[id++];
Edge.push_back({s,p});
if(--D[s]==1)p=s;else break;
}
while(p<i);
}
for(int i=0;i<n;i++)if(~D[i])u.push_back(i);
Edge.push_back({u[0],u[1]});
return Edge;
}
Etype Chain(int n,bool op=false){
Etype Edge;
for(int i=1;i<n;i++)
if(op)
Edge.push_back({i,i-1});
else
Edge.push_back({i-1,i});
return Edge;
}
Etype Chrys(int n,int rot=0,bool op=false){
if(rot>=n||rot<0)
rot=0;
Etype Edge;
for(int i=0;i<n;i++)if(i!=rot){
if(op)
Edge.push_back({rot,i});
else
Edge.push_back({i,rot});
}
return Edge;
}
Etype Dande(int n,int mainp=-1,bool op=false){
if(mainp>=n||mainp<0)
mainp=n/2;
Etype Edge;
if(op){
for(int i=0;i<mainp;i++)
Edge.push_back({i,i+1});
for(int i=mainp+1;i<n;i++)
Edge.push_back({i,mainp});
}else{
for(int i=0;i<mainp;i++)
Edge.push_back({i,mainp});
for(int i=mainp+1;i<n;i++)
Edge.push_back({i-1,i});
}
return Edge;
}
Vtype RandVal(int n,int up=2147483647,int down=0,random_t&rng=rnd){
Vtype Ans(n);
for(auto&e:Ans)
e=rng.next(down,up);
return Ans;
}
EVtype UpdateVal(Etype E,Vtype Val){
if(E.size()!=Val.size())
exit(0);
EVtype Ans;
int p=0;
for(auto e:E)
Ans.push_back({e,Val[p++]});
return Ans;
}
Etype RemoveVal(EVtype E){
Etype Ans;
for(auto e:E)
Ans.push_back(e.first);
return Ans;
}
Vtype GetVal(EVtype E){
Vtype Ans;
for(auto e:E)
Ans.push_back(e.second);
return Ans;
}
std::vector<int>Way[60005];
bool Gone[60005];
void dfs(int p){
if(Gone[p])return;
Gone[p]=1;
for(auto s:Way[p])
dfs(s);
}
bool Valid(int n,Etype E){
if(E.size()!=n-1u)
return false;
for(int i=0;i<n;i++)
Way[i].clear(),Gone[i]=false;
for(auto e:E){
if(e.first<0||e.second<0||e.first>=n||e.second>=n)
return false;
Way[e.first].push_back(e.second);
Way[e.second].push_back(e.first);
}
dfs(0);
for(int i=0;i<n;i++)
if(!Gone[i])
return false;
return true;
}
bool match(char*Sys,const char*C){
while(*Sys&&*C)if(*(Sys++)!=*(C++))return false;
return*Sys==*C;
}
int main(int argc,char**argv)
{
registerGen(argc,argv,1);
freopen(argv[1],"w",stdout);
int n=atoi(argv[2]),q=atoi(argv[3]);
n=rnd.wnext(1,n,1000),q=rnd.wnext(1,q,1000);
Etype E;
if(match(argv[4],"chain"))
E=Chain(n);
else if(match(argv[4],"chrys"))
E=Chrys(n);
else if(match(argv[4],"dande"))
E=Dande(n);
else if(match(argv[4],"r1"))
E=RandTree1(n,argc<=5?0:atoi(argv[5]));
else
E=RandTree2(n,argc<=5?0:atoi(argv[5]));
Relabel(E,1,1);
if(!Valid(n,E)){
fputs("qwq",stderr);
puts("Invalid Data"),fflush(stdout);
return 0;
}
Addlabel(E,1);
EVtype E2=UpdateVal(E,RandVal(n-1,1000,1));
printf("%d %d\n",n,q);
for(auto e:E2)
printf("%d %d %d\n",e.first.first,e.first.second,e.second);
Vtype A(n,0);
while(q--){
int p=rnd.next(n);
int v=rnd.next(std::max(-A[p],-1000),1000);
A[p]+=v;
printf("%d %d\n",p+1,v);
}
return 0;
}
然后就爽了。
使用我之前造数据的套路生成器,使用了 cpl1.cpp
与 cpl2.cpp
。
cpl1.cpp
:
// gen input
#include <stdio.h>
#include <stdlib.h>
bool match(char*Sys,const char*C){
while(*Sys&&*C)if(*(Sys++)!=*(C++))return false;
return*Sys==*C;
}
void runcode(char*Sys){
fprintf(stderr,"%s\n",Sys),fflush(stderr);
system(Sys);
}
char C[100005],D[300005],Sys[500005];
int main()
{
system("g++ gen.cpp -o gen -Wall -std=c++11 -lm -Wl,--stack=33554432");
FILE*fin=fopen("data_task.txt","r");
int l,r;
while(fscanf(fin,"%d%d",&l,&r)==2)
{
fgets(C,100000,fin);
char*c=C;
while(*c&&*c!='\r'&&*c!='\n')c++;
*c='\0';
sprintf(D,"gen %s",C);
while(l<=r)
{
sprintf(Sys,D,l);
runcode(Sys);
l++;
}
}
fclose(fin);
return 0;
}
cpl2.cpp
:
// gen answer
#include <stdio.h>
#include <stdlib.h>
bool match(char*Sys,const char*C){
while(*Sys&&*C)if(*(Sys++)!=*(C++))return false;
return*Sys==*C;
}
void runcode(char*Sys){
fprintf(stderr,"%s\n",Sys),fflush(stderr);
system(Sys);
}
char C[100005],D[300005],Sys[500005];
int main()
{
system("g++ std.cpp -o std -Wall -std=c++11 -lm -Wl,--stack=33554432");
FILE*fin=fopen("data_name.txt","r");
int l,r;
while(fscanf(fin,"%d%d",&l,&r)==2)
{
fgets(C,100000,fin);
char*c=C;
while(*c&&*c!='\r'&&*c!='\n')c++;
*c='\0';
sprintf(D,"std < %s.in > %s.ans",C,C);
while(l<=r)
{
sprintf(Sys,D,l,l);
runcode(Sys);
l++;
}
}
fclose(fin);
return 0;
}
然后 data_task.txt
与 data_name.txt
这么填。
data_task.txt
:
1 5 data\game_small%d.in 5000 2000 chain
6 10 data\game_small%d.in 5000 2000 chrys
11 15 data\game_small%d.in 5000 2000 dande
16 20 data\game_small%d.in 5000 2000 r1
21 25 data\game_small%d.in 5000 2000 r2
1 1 data\game%d.in 5000 2000 chain
2 2 data\game%d.in 5000 2000 chrys
3 3 data\game%d.in 5000 2000 dande
4 4 data\game%d.in 5000 2000 r1
5 5 data\game%d.in 5000 2000 r2
6 7 data\game%d.in 60000 60000 chain
8 9 data\game%d.in 60000 60000 chrys
10 11 data\game%d.in 60000 60000 dande
12 13 data\game%d.in 60000 60000 r1
14 15 data\game%d.in 60000 60000 r2
16 16 data\game%d.in 60000 60000 r1 10000
17 17 data\game%d.in 60000 60000 r1 -10000
18 18 data\game%d.in 60000 60000 r2 10000
19 20 data\game%d.in 60000 60000 r2 -10000
21 21 data\game%d.in 60000 60000 chain
22 22 data\game%d.in 60000 60000 chrys
23 23 data\game%d.in 60000 60000 dande
24 24 data\game%d.in 60000 60000 r1
25 25 data\game%d.in 60000 60000 r2
data_name.txt
:
1 25 data\game_small%d
1 25 data\game%d
造完后本地用 Lemon 挑了四篇题解测了一下,结果是这样的:结果文件下载链接。(呜呜本地 LemonLime 打不开,只好用 Lemon 了)
那么这就是关于加强一道题目的事情了,大家有没有觉得很神奇呢?快来在评论区与小编互动吧!
本文来自博客园,作者:myee,转载请注明原文链接:https://www.cnblogs.com/myee/p/how-to-strongthen-a-problem.html