这次比赛打的很有趣啊。
Challenge大战!
A Good Set
题意简述
定义“好集合”为:集合中元素两两不同,权值均在
[1,500]
,且不存在三个元素
a,b,c
使得
a+b=c
。
输出大小为
n
的“好集合”
数据范围
思路
一开始想二进制之类的balabala……
最后发现输出最大的前
n
个数不就行了……
Naive!
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x)
{
char ch=getchar();
for (x=0;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
}
int T,n;
int main()
{
read(T);
while (T--)
{
read(n);
for (int i=1;i<=n;i++)
printf("%d%c",501-i," \n"[i==n]);
}
return 0;
}
Xenny and Coin Rankings
题意简述
给二维坐标定义了一个序。
大体图形是这样子的:
然后问你一个矩形范围内标号最大的点是多少。
数据范围
1≤T≤100
1≤u,v≤109
思路
标号最大的肯定是右上角的啊…
公式题。
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x)
{
char ch=getchar();
for (x=0;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
}
typedef long long ll;
int T,u,v,x;
ll ans;
int main()
{
read(T);
while (T--)
{
read(u),read(v);
x=u+v;
ans=1LL*(1+x)*x/2;
ans+=u+1;
printf("%lld\n",ans);
}
return 0;
}
Chef and the Feast
题意简述
n
盘菜,每盘菜有美味度
每次吃,假设吃掉
k
盘,你将获得
最大化幸福度之和。
数据范围
1≤T≤8
1≤n≤105
0≤|ai|≤108
思路
贪心。
一开始想的正的都在一起选,负的一个一个选。
wawawawawa。
后来撕烤了一下。
猜了个结论:一起选的一定是从大到小连续的一段区间,剩下的单独选。
排序,从大到小选,如果加上这盘菜还能使答案
>0
就选……
正确性证明见wa爷爷blog:http://wronganswer.blog.uoj.ac/blog/2667
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x)
{
char ch=getchar();
int f=1;
for (x=0;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());
if (ch=='-') f=-1,ch=getchar();
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
x*=f;
}
typedef long long ll;
int T,n;
int seq[100010];
ll u,sum,ans,size;
int main()
{
read(T);
while (T--)
{
read(n);
for (int i=1;i<=n;i++)
read(seq[i]);
sort(seq+1,seq+n+1);
sum=0,ans=0,size=0;
for (int i=n;i>=1;i--)
if (seq[i]*size+sum >=0)
sum+=seq[i],size++;
else
{
for (int j=i;j>=1;j--)
ans+=seq[j];
break;
}
ans+=sum*size;
printf("%lld\n",ans);
}
return 0;
}
Pairwise union of sets
题意简述
给你
n
个集合。
每个集合的元素
问有多少对集合,它们的并集为
1
到
数据范围
1≤T≤10
1≤n,k≤2500
∑sizei≤10000
思路
看到题第一感随手打了个bitset…
TLE……
加了个优化,如果两个集合的size之和都到不了
k
就不计算它们的并。
TLE……
随眼一瞟看到元素个数之和
按照
k
大小分类,小的就bitset开小一点……
然后就A了……
然后就过了……
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x)
{
char ch=getchar();
for (x=0;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
}
int T,n,k,ans,u,v;
int num[2510];
void work1000()
{
bitset<2510> B[2510];
for (int i=1;i<=n;i++)
B[i].reset();
memset(num,0,sizeof(num));
for (int i=1;i<=n;i++)
{
read(u);
for (int j=1;j<=u;j++)
{
read(v);
B[i].set(v);
num[i]++;
}
}
ans=0;
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
if (num[i]+num[j]>=k && (B[i]|B[j]).count()==k)
ans++;
printf("%d\n",ans);
}
void work100()
{
bitset<110> B[2510];
for (int i=1;i<=n;i++)
B[i].reset();
memset(num,0,sizeof(num));
for (int i=1;i<=n;i++)
{
read(u);
for (int j=1;j<=u;j++)
{
read(v);
B[i].set(v);
num[i]++;
}
}
ans=0;
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++)
if (num[i]+num[j]>=k && (B[i]|B[j]).count()==k)
ans++;
printf("%d\n",ans);
}
int main()
{
read(T);
while (T--)
{
read(n),read(k);
if (k<=100)
work100();
else
work1000();
}
return 0;
}
Triplets
题意简述
给定三个序列
A,B,C
,
f(x,y,z)=(x+y)(y+z)[x≤y][z≤y]
求
∑i,j,kf(Ai,Bj,Ck)
数据范围
1≤T≤10
1≤n≤105
思路
two pointers。
都排序之后枚举
j
,
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x)
{
char ch=getchar();
for (x=0;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
}
typedef long long ll;
#define MAXN 100010
const int mo=1000000007;
int T,a,b,c;
int A[MAXN],B[MAXN],C[MAXN];
ll suma,sumc,ans;
int main()
{
read(T);
while (T--)
{
read(a),read(b),read(c);
for (int i=1;i<=a;i++)
read(A[i]);
for (int i=1;i<=b;i++)
read(B[i]);
for (int i=1;i<=c;i++)
read(C[i]);
sort(A+1,A+a+1);
sort(B+1,B+b+1);
sort(C+1,C+c+1);
suma=0,sumc=0,ans=0;
for (int i=1,j=1,k=1;j<=b;j++)
{
while (i<=a && A[i]<=B[j]) suma=(suma+A[i++])%mo;
while (k<=c && C[k]<=B[j]) sumc=(sumc+C[k++])%mo;
ans=(ans+1LL*(i-1)*(k-1)%mo*B[j]%mo*B[j] + suma*(k-1)%mo*B[j] + sumc*(i-1)%mo*B[j] + suma*sumc)%mo;
}
printf("%lld\n",ans);
}
return 0;
}
Chef and Prime Queries
题意简述
给出长度为
n
的数列
设
Ai=pk11pk22…
每次询问
∑Ri=L∑pkk[x≤p≤y]
数据范围
1≤n,q≤105
1≤ai,x,y≤106
思路
稍微转化一下就会发现这是一个矩形和问题。
离线询问,将每个询问拆成
L,R
两个,拆分之后的询问就变成了
[x,y]
区间已有的质数个数累加和是多少。
排序。顺序扫描
A
,添加质数,回答询问。
质因子个数
总复杂度
O(Td(q+n)logn)
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x)
{
char ch=getchar();
for (x=0;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
}
int n,q,t1,t2,t3,t4,Q_cnt,now,tmp;
int a[100010],ans[100010];
int p_cnt,prime[100010],mn[1000010],go[1000010],ti[1000010],idx[1000010];
bool not_p[1000010];
void sieve(int n)
{
not_p[1]=1;
for (int i=2;i<=n;i++)
{
if (!not_p[i])
{
prime[++p_cnt]=i;
mn[i]=p_cnt;
go[i]=1;
ti[i]=1;
}
for (int j=1;i*prime[j]<=n && j<=p_cnt;j++)
{
not_p[i*prime[j]]=1;
if (i%prime[j]==0)
{
mn[i*prime[j]]=mn[i];
go[i*prime[j]]=go[i];
ti[i*prime[j]]=ti[i]+1;
break;
}
mn[i*prime[j]]=j;
go[i*prime[j]]=i;
ti[i*prime[j]]=1;
}
}
p_cnt=0;
for (int i=1;i<=n;i++)
{
if (!not_p[i]) p_cnt++;
idx[i]=p_cnt;
}
}
struct BIT{
static const int size=100000;
int d[100010];
BIT()
{
memset(d,0,sizeof(d));
}
int lowbit(int x)
{
return x&(-x);
}
void modify(int pos,int val)
{
for (;pos<=size;pos+=lowbit(pos))
d[pos]+=val;
}
int query(int l,int r)
{
int ret=0;
for (;r;r-=lowbit(r))
ret+=d[r];
for (;l;l-=lowbit(l))
ret-=d[l];
return ret;
}
}T;
struct Query{
int pos,x,y,ty,id;
Query(int _pos=0,int _x=0,int _y=0,int _ty=0,int _id=0)
{
pos=_pos,x=_x,y=_y,ty=_ty,id=_id;
}
bool operator < (const Query &n1) const
{
return pos<n1.pos;
}
void print()
{
printf("pos=%d,[%d,%d],id=%d\n",pos*ty,x,y,id);
}
}Q[200010];
int main()
{
sieve(1000000);
read(n);
for (int i=1;i<=n;i++)
read(a[i]);
read(q);
for (int i=1;i<=q;i++)
{
read(t1),read(t2),read(t3),read(t4);
Q[++Q_cnt]=Query(t1-1,idx[t3-1],idx[t4],-1,i);
Q[++Q_cnt]=Query(t2,idx[t3-1],idx[t4],1,i);
}
sort(Q+1,Q+Q_cnt+1);
now=1;
for (int i=1;i<=Q_cnt;i++)
{
while (now<=Q[i].pos)
{
tmp=a[now];
while (tmp!=1)
{
T.modify(mn[tmp],ti[tmp]);
tmp=go[tmp];
}
now++;
}
ans[Q[i].id]+=Q[i].ty*T.query(Q[i].x,Q[i].y);
}
for (int i=1;i<=q;i++)
printf("%d\n",ans[i]);
return 0;
}
Cloning
题意简述
定义两个长度相等的子串是“相似的”:将它们的元素分别排序后,一一对应,最多只有一位不同。
给出长度为
n
的数列
每次询问两个长度相等子串是否是相似的。
数据范围
1≤T≤3
1≤n,Ai≤105
思路
hash+主席树。
按照权值哈希,权值为
x
的元素对哈希值的贡献为
在主席树上,两个区间一起跑,找到哈希相同的最大前缀和最大后缀。
判断一下即可。
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x)
{
char ch=getchar();
for (x=0;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
}
#define MAXN 100010
#define MAXV 100000
typedef unsigned long long ull;
const ull base=13331;
ull basepow[MAXN],val1,val2;
int T,n,q,l1,r1,l2,r2,posl,posr;
int seq[MAXN];
namespace PT
{
struct Node{
Node *ch[2];
ull sum;
void pushup()
{
sum=ch[0]->sum+ch[1]->sum;
}
}*null=new Node;
Node pool[MAXN*30];
Node *tail=pool;
Node *NewNode()
{
Node *p=tail++;
p->ch[0]=p->ch[1]=null;
p->sum=0;
return p;
}
Node *Root[MAXN];
void init()
{
null->ch[0]=null->ch[1]=null;
null->sum=0;
tail=pool;
for (int i=0;i<=n;i++)
Root[i]=NewNode();
}
void add(int pos,int l,int r,Node *node,Node *pre)
{
if (l==r)
{
node->sum=pre->sum+basepow[pos];
return;
}
int mid=(l+r)>>1;
if (pos<=mid)
{
if (node->ch[0]==null)
node->ch[0]=NewNode();
node->ch[1]=pre->ch[1];
add(pos,l,mid,node->ch[0],pre->ch[0]);
}
else
{
if (node->ch[1]==null)
node->ch[1]=NewNode();
node->ch[0]=pre->ch[0];
add(pos,mid+1,r,node->ch[1],pre->ch[1]);
}
node->pushup();
}
int queryl(int l,int r,Node *l1,Node *r1,Node *l2,Node *r2)
{
if (l==r) return l;
int mid=(l+r)>>1;
if (r1->ch[0]->sum - l1->ch[0]->sum != r2->ch[0]->sum - l2->ch[0]->sum)
return queryl(l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0]);
else
return queryl(mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]);
}
int queryr(int l,int r,Node *l1,Node *r1,Node *l2,Node *r2)
{
if (l==r) return l;
int mid=(l+r)>>1;
if (r1->ch[1]->sum - l1->ch[1]->sum != r2->ch[1]->sum - l2->ch[1]->sum)
return queryr(mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]);
else
return queryr(l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0]);
}
ull judge(int L,int R,int l,int r,Node *l1,Node *r1,Node *l2,Node *r2)
{
if (R<l || r<L) return 0;
if (L<=l && r<=R) return r1->sum - l1->sum + r2->sum - l2->sum;
int mid=(l+r)>>1;
return judge(L,R,l,mid,l1->ch[0],r1->ch[0],l2->ch[0],r2->ch[0])+judge(L,R,mid+1,r,l1->ch[1],r1->ch[1],l2->ch[1],r2->ch[1]);
}
}
int main()
{
basepow[0]=1;
for (int i=1;i<=100000;i++)
basepow[i]=basepow[i-1]*base;
read(T);
while (T--)
{
read(n),read(q);
PT::init();
for (int i=1;i<=n;i++)
{
read(seq[i]);
PT::add(seq[i],1,MAXV,PT::Root[i],PT::Root[i-1]);
}
for (int i=1;i<=q;i++)
{
read(l1),read(r1),read(l2),read(r2);
val1=PT::Root[r1]->sum - PT::Root[l1-1]->sum;
val2=PT::Root[r2]->sum - PT::Root[l2-1]->sum;
if (val1==val2)
puts("YES");
else
{
posl=PT::queryl(1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2]);
posr=PT::queryr(1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2]);
if ((posl+1>posr-1 || judge(posl+1,posr-1,1,MAXV,PT::Root[l1-1],PT::Root[r1],PT::Root[l2-1],PT::Root[r2])==0) && (val1+basepow[posl]==val2+basepow[posr] || val1+basepow[posr]==val2+basepow[posl]))
puts("YES");
else
puts("NO");
}
}
}
return 0;
}
Euler Sum
题意简述
求 ∑ni=1⌊ie⌋
数据范围
1≤n≤104000
代码长度限制1KB = =(真的大丈夫?
思路
首先语言肯定选个自带高精度的…现学了一下PY…
然后应该用什么算法呢…找了半天e的性质无果…
忘了墩爷还是YJQ随口一句类欧几里得…好嘛…现学一下类欧。
类欧好像有两种形式,一种是分数型
⌊ax+bc⌋
这样…然后你就转换一下枚举顺序balabala
另一种是一般型
⌊kx⌋
这样…然后你就每次讨论一下
k
,
然后我就xjb用泰勒展开强行把
e
拟合成分数,跑了一下分数型…然后就过了…
考后想了下可不可以用
吐槽一下PY还限制递归深度……
代码
import sys
sys.setrecursionlimit(1000000000)
def solve(A,B,C,n):
if (A==0):
return (n+1)*(B//C)
if (A>=C):
return solve(A%C,B,C,n)+n*(n+1)//2*(A//C)
if (B>=C):
return solve(A,B%C,C,n)+(n+1)*(B//C)
m=(A*n+B)//C
return n*m-solve(C,C-B-1,A,m-1)
n=int(input())
C=1
A=1
lim=3000
for i in range (1,lim):
C*=i
for i in range (1,lim):
A=(A*i)+1
print(solve(A,0,C,n))
Persistent oak
题意简述
给你一棵树,树上每个节点都有一个重量承受度
wi
。
当其子树的重量之和
>wi
,那么这棵子树就会断掉…如果有多个节点满足,选择最远离树根的节点。
有两个操作:
1.某个节点长出了重量为
x
的果实。
2.询问一棵子树内的果实数量,同时清空。
所有操作可持久化,每次操作会告诉你前驱版本的编号…
数据范围
1≤n,q≤105
1≤wi,x≤107
思路
先来考虑不持久化怎么做。
树链剖分,维护
sum
维护
wi−sum
的最小值维护一个加标记和一个清空标记。
1.操作就在链上跳,找到第一个满足要求的操作,子树清空,找不到就将到根的路径所有节点维护的那个最小值减去一个值。
2.子树查询
sum
,子树清空。
可持久化的话…加标记标记永久化一下。
清空的话…直接连到0号版本的树上(还有这种操作?.jpg),然后再将从父亲到根的路径都加上sum。
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x,char ch=getchar())
{
for (x=0;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=getchar());
}
#define MAXN 100010
#define INF 1LL<<60
typedef long long ll;
int T,n,m,ord,sta,opt,u,v,t;
int seq[MAXN],size[MAXN],son[MAXN],fa[MAXN],top[MAXN],deep[MAXN],dfn[MAXN],rdfn[MAXN];
ll w[MAXN],FK;
namespace PT
{
struct Node{
Node *ch[2];
ll mn,add,sum;
void pushup()
{
mn=min(ch[0]->mn,ch[1]->mn)+add;
sum=ch[0]->sum+ch[1]->sum;
}
}*null=new Node;
Node pool[MAXN*400];
Node *tail;
Node *ver[MAXN];
Node *NewNode(Node *f=0)
{
Node *p=tail++;
if (f)
{
p->ch[0]=f->ch[0];p->ch[1]=f->ch[1];
p->mn=f->mn;
p->add=f->add;
p->sum=f->sum;
}
else
p->ch[0]=p->ch[1]=null;
return p;
}
Node *build(int l,int r)
{
Node *ret=NewNode();
if (l==r)
{
ret->mn=w[seq[l]];
ret->add=0;
ret->sum=0;
return ret;
}
int mid=(l+r)>>1;
ret->ch[0]=build(l,mid);
ret->ch[1]=build(mid+1,r);
ret->pushup();
return ret;
}
void init()
{
tail=pool;
null->ch[0]=null->ch[1]=null;
null->mn=INF;
null->sum=0;
null->add=0;
ver[0]=build(1,n);
}
void add(int pos,int l,int r,Node* &now,ll val)
{
now=NewNode(now);
if (l==r)
{
now->sum+=val;
return;
}
int mid=(l+r)>>1;
if (pos<=mid)
add(pos,l,mid,now->ch[0],val);
else
add(pos,mid+1,r,now->ch[1],val);
now->pushup();
}
void Iadd(int L,int R,int l,int r,Node* &now,ll val)
{
now=NewNode(now);
if (L<=l && r<=R)
{
now->add+=val;
now->mn+=val;
return;
}
int mid=(l+r)>>1;
if (L<=mid)
Iadd(L,R,l,mid,now->ch[0],val);
if (R>mid)
Iadd(L,R,mid+1,r,now->ch[1],val);
now->pushup();
}
void clear(int L,int R,int l,int r,ll tag,Node* &now,Node *pre)
{
if (L<=l && r<=R)
{
FK+=now->sum;
now=NewNode(pre);
now->add-=tag;
now->mn-=tag;
return;
}
now=NewNode(now);
int mid=(l+r)>>1;
if (L<=mid)
clear(L,R,l,mid,tag+now->add,now->ch[0],pre->ch[0]);
if (R>mid)
clear(L,R,mid+1,r,tag+now->add,now->ch[1],pre->ch[1]);
now->pushup();
}
int query_mn(int L,int R,int l,int r,Node *now,ll val)
{
if (now->mn >= val) return 0;
if (l==r) return seq[l];
int mid=(l+r)>>1;
if (R>mid)
{
int ret=query_mn(L,R,mid+1,r,now->ch[1],val-now->add);
if (ret) return ret;
}
if (L<=mid)
return query_mn(L,R,l,mid,now->ch[0],val-now->add);
return 0;
}
void debug(int l,int r,Node *now)
{
printf("[%d,%d]:mn=%lld,add=%lld,sum=%lld\n",l,r,now->mn,now->add,now->sum);
if (l==r)
return;
int mid=(l+r)>>1;
debug(l,mid,now->ch[0]);
debug(mid+1,r,now->ch[1]);
}
}
struct edge{
int s,t,next;
}e[MAXN<<1];
int head[MAXN],cnt;
void addedge(int s,int t)
{
e[cnt].s=s;e[cnt].t=t;e[cnt].next=head[s];head[s]=cnt++;
e[cnt].t=s;e[cnt].s=t;e[cnt].next=head[t];head[t]=cnt++;
}
void dfs(int node,int lastfa,int de)
{
fa[node]=lastfa;
deep[node]=de;
size[node]=1;
son[node]=0;
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa)
{
dfs(e[i].t,node,de+1);
size[node]+=size[e[i].t];
if (size[e[i].t]>size[son[node]])
son[node]=e[i].t;
}
}
void dfs2(int node,int lastfa,int tp)
{
top[node]=tp;
dfn[node]=++ord;
seq[ord]=node;
if (son[node])
dfs2(son[node],node,tp);
for (int i=head[node];i!=-1;i=e[i].next)
if (e[i].t!=lastfa && e[i].t!=son[node])
dfs2(e[i].t,node,e[i].t);
rdfn[node]=ord;
}
int get_mn(int sta,int u,ll v)
{
while (u)
{
int ret=PT::query_mn(dfn[top[u]],dfn[u],1,n,PT::ver[sta],v);
if (ret) return ret;
u=fa[top[u]];
}
return 0;
}
void mo_add(int sta,int u,ll v)
{
while (u)
{
PT::Iadd(dfn[top[u]],dfn[u],1,n,PT::ver[sta],v);
u=fa[top[u]];
}
return;
}
int main()
{
read(T);
while (T--)
{
read(n),read(m);n++;
memset(head,0xff,sizeof(head));
cnt=0;
for (int i=2;i<=n;i++)
{
read(u);u++;
addedge(i,u);
read(w[i]);
}
w[1]=INF;
dfs(1,0,1);
ord=0;
dfs2(1,1,1);
PT::init();
for (int i=1;i<=m;i++)
{
read(sta),read(opt),read(u);u++;
if (opt==1)
{
read(v);
t=get_mn(sta,u,v);
printf("%d\n",max(0,t-1));
if (t)
{
PT::ver[i]=PT::ver[sta];
FK=0;
PT::clear(dfn[t],rdfn[t],1,n,0,PT::ver[i],PT::ver[0]);
mo_add(i,fa[t],FK);
}
else
{
PT::ver[i]=PT::ver[sta];
PT::add(dfn[u],1,n,PT::ver[i],v);
mo_add(i,u,-v);
}
}
else
{
PT::ver[i]=PT::ver[sta];
FK=0;
PT::clear(dfn[u],rdfn[u],1,n,0,PT::ver[i],PT::ver[0]);
printf("%lld\n",FK);
mo_add(i,fa[u],FK);
}
}
}
return 0;
}
Saboteur (Challenge)
题意简述
给你一个图,让你删除某些点,使得剩下的点形成一棵树。
最小化删除权值和。
数据范围
1≤n≤104
1≤m≤5×104
子任务:
1.
n≤20
2.
n≤40
3.
n=m
4.
m≤n+3
5.完全图
6.轮子图
7.随机图
思路
这题甩锅给同学了,代码就不发了……
子任务1暴力,子任务3基环树DP一下,子任务4缩一缩点,子任务5保留两个权值最大的,子任务6两种情况,中间点删了就贪心,不删就DP一下。
子任务7
随机一个加点顺序,如果不成环就加,最后选权值最大的树。
多次随机,贪心优化。
子任务2用随机跑了。
被日本min_25踩了…代码1千行…
OI选手和人家完全没法比啊……