hdu2020多校2

比赛链接

题目链接

一些总结

做的时候越来越困,导致一堆那种还算简单的题最后想不到了。

其实也不只是困的原因,更重要的还是当遇到困难的时候真的应该安静下来努力克服,或者重新开会理一遍思路,这样就会快点想到,以免浪费太多没有意义的时间。

比如下面的一道裸费用流题,自己想来想去,先是想了想随机,然后再想DP,这是就应该静下心来,思考自己的方案是不是对的。看到匹配问题的时候就应该一开始就想到网络流类的问题才行。

A. Total Eclipse

题意

给你一个无向图,上面每个点有权值 $b_i$。进行若干次操作,每次选择一个连通块,然后将连通块内的 $b_i$ 减去 $1$。问至少多少次操作,使得 $b_i$ 全变为 $0$。

$n\le 10^5,m\le 2\times 10^5$。

题解

这是第一道做出来的题。

显然贪心,每次选择一个极大连通块内 $b_i$ 最小的点,然后将这个连通块的所有点权都减去 $b_i$,然后删掉 $i$ 这个点。

但是我们无法维护删掉后的连通性。

考虑倒着做,那么就只需要维护加点之后的连通性就可以了。

时间复杂度 $O(n\log n)$。

程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())
const int N=100010;
bool bo[N],vis[N];
int a[N],id[N],fa[N],mi[N];
ll ans;
int n,m;
vector<int> adj[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void merge(int x,int y)
{
y=find(y);
if(x==y) return;
fa[y]=x;
mi[x]=min(mi[x],mi[y]);
}
inline void add(int x,int y)
{
adj[x].pb(y); adj[y].pb(x);
}
int main()
{
CASET
{
n=read(); m=read(); ans=0;
fo(i,1,n) adj[i].clear();
fo(i,1,n) a[i]=read(),id[i]=i,fa[i]=i,mi[i]=a[i],vis[i]=0;
fo(i,1,m) add(read(),read());
sort(id+1,id+n+1,[&](const int &x,const int &y){return a[x]>a[y];});
fo(i,1,n)
{
int u=id[i]; vis[u]=1;
for(auto v:adj[u])
if(vis[v])
{
int w=find(v);
if(!bo[w])
{
bo[w]=1;
ans+=mi[w]-a[u];
}
}
for(auto v:adj[u]) if(vis[v]) bo[find(v)]=0;
for(auto v:adj[u]) if(vis[v]) merge(find(v),u);
}
fo(i,1,n) if(find(i)==i) ans+=mi[i];
printf("%lld\n",ans);
}
return 0;
}

E. New Equipments

题意

$n$ 个工人,$m$ 件设备编号 $[1,m]$。第 $i$ 个人选第 $j$ 个设备花费 $a_ij^2+b_ij+c_i$ ,对于每个 $k\in[1,n]$,求在 $n$ 个人里选 $k$ 个和设备配对的最小花费是多少。每个设备最多只能被匹配一个工人。

$T\le 10,n\leq 50,n\le m\le 10^8,b_i^2\geq 4a_ic_i,1\le a_i\le 10,|b_i|\le 10^8,0\le c_i\leq 10^{16}$

题解

因为 $a_i>0$,所有的二次函数有最下值。因此对于一个工人而言,他肯定会贪心的选择 $-\frac{b_i}{2a_i}$ 附近的设备。

这个附近的设备可以表示成一个长度为 $n$ 的区间。

那么能被选到的设备就最多只有 $n^2$ 个。

那么把工人看成一个点,放在左边;有可能被选上的设备放在右边。

随着 $k$ 递增,每次将费用加 $1$ 就好了。

而费用流的时间复杂度是流量乘上最短路的复杂度。

spfa费用流复杂度为 $O(n^5)$,dijkstra优化的费用流复杂度为 $O(n^4+n^3\log n)=O(n^4)$。常数都较小。

程序

dijkstra优化版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline ll read()
{
ll x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())

namespace G{
#define N 3000
const int M=100000;
const ll inf=4e18;
int s,t,ss;
int ver[M],val[M];
ll cost[M];
int ne[M],head[N],tot;
inline void add(int x,int y,int v,ll c)
{
ver[++tot]=y; val[tot]=v; cost[tot]=c; ne[tot]=head[x]; head[x]=tot;
ver[++tot]=x; val[tot]=0; cost[tot]=-c;ne[tot]=head[y]; head[y]=tot;
}
ll h[N],dis[N];
bool vis[N];
void init()
{
fo(i,0,t) head[i]=0;
tot=1;
}
void spfa(int s,int t)
{
for(int i=0;i<=t;i++) h[i]=inf;
queue<int> q;
for(h[s]=0,q.push(s);!q.empty();)
{
int u=q.front(); q.pop();
for(int i=head[u],v;i;i=ne[i])
if(val[i]&&h[v=ver[i]]>h[u]+cost[i])
{
h[v]=h[u]+cost[i];
if(!vis[v]) q.push(v),vis[v]=1;
}
vis[u]=0;
}
}
struct node{
int u; ll dis;
friend inline bool operator<(const node &A,const node &B){return A.dis>B.dis;}
};
int pv[N],pe[N];
priority_queue<node> q;
inline ll work()
{
int flow=0;
ll co=0;
for(;;)
{
for(int i=0;i<=t;i++) dis[i]=inf;
for(dis[s]=0,q.push((node){s,dis[s]});!q.empty();)
{
node now=q.top(); q.pop();
int u=now.u;
if(dis[u]<now.dis) continue;
for(int i=head[u],v;i;i=ne[i])
if(val[i])
{
v=ver[i];
if(dis[v]+h[v]>dis[u]+h[u]+cost[i])
dis[v]=dis[u]+h[u]+cost[i]-h[v],
q.push((node){v,dis[v]}),
pv[v]=u,pe[v]=i;
}
}
if(dis[t]==inf) break;
for(int i=0;i<=t;i++) h[i]+=dis[i];
int tmp=1e9;
for(int u=t;u!=s;u=pv[u]) tmp=min(tmp,val[pe[u]]);
flow+=tmp; co+=h[t]*tmp;
for(int u=t,i;u!=s;u=pv[u]) i=pe[u],val[i]-=tmp,val[i^1]+=tmp;
}
return co;
}
inline void solve(int n)
{
add(s,ss,1,0);
int k=tot-1;
spfa(s,t);
ll sum=0;
fo(i,1,n)
{
printf(((i==n)?"%lld\n":"%lld "),sum+=work());
val[k]++
}
}
#undef N
}

const int N=53;
int n,m,L[N],R[N];
ll a[N],b[N],c[N];
inline ll F(ll x,int j)
{
return x*(x*a[j]+b[j])+c[j];
}
vector<int> vec;
int main()
{
CASET
{
n=read(); m=read(); vec.clear();
fo(i,1,n)
{
a[i]=read(),b[i]=read(),c[i]=read();
ll x=-b[i]/(2ll*a[i]);
if(x<=0) L[i]=1,R[i]=n;
else
{
if(x>=27)
{
if(x+26<=m) L[i]=x-26,R[i]=x+26;
else L[i]=max(1,m-n),R[i]=m;
}
else L[i]=1,R[i]=n;
}
fo(j,L[i],R[i]) vec.pb(j);
}
sort(all(vec));
vec.resize(unique(all(vec))-vec.begin());
G::init();
G::s=0; G::ss=1; G::t=vec.size()+n+3;
fo(i,1,n)
fo(j,L[i],R[i])
G::add(i+1,lower_bound(all(vec),j)-vec.begin()+n+2,1,F(j,i));
fo(i,1,n) G::add(G::ss,i+1,1,0);
ff(j,0,vec.size()) G::add(j+n+2,G::t,1,0);
G::solve(n);
}
return 0;
}

F. The Oculus

题解

暴力哈希即可,我这里写了双哈希。

程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())
const ll mod1=998244853;
const ll mod2=2147483647;
ll F[2000005],G[2000005];
map<pair<ll,ll>,int> ma;
int main()
{
F[1]=1; F[2]=2;
fo(i,3,2000000)
{
F[i]=F[i-1]+F[i-2];
F[i]>=mod1?F[i]-=mod1:0;
}
G[1]=1; G[2]=2;
fo(i,3,2000000)
{
G[i]=G[i-1]+G[i-2];
G[i]>=mod2?G[i]-=mod2:0;
}
fo(i,1,2000000) ma[mp(F[i],G[i])]=i;
ll n1,n2,m1,m2,k1,k2;
int n,m,k;
CASET
{
n=read(); n1=n2=0;
fo(i,1,n)
{
if(read()) (n1=(n1+F[i])%mod1,n2=(n2+G[i])%mod2);
}
m=read(); m1=m2=0;
fo(i,1,m)
if(read())
{
m1=(m1+F[i])%mod1,m2=(m2+G[i])%mod2;
}
k=read(); k1=k2=0;
fo(i,1,k)
if(read())
{
k1=(k1+F[i])%mod1,k2=(k2+G[i])%mod2;
}
n1=(n1*m1-k1+mod1)%mod1; n2=(n2*m2-k2+mod2)%mod2;
printf("%d\n",ma[mp(n1,n2)]);
}
return 0;
}

G. In Search of Gold

题意

一棵树,边有两种权值 $a_i,b_i$。有 $k$ 条边可以选择 $a_i$,剩下的 $n-1-k$ 可以选择 $b_i$。问这个树的直径的最小值。

$n\leq 20000,k\le 20,\sum n\le 2\times 10^5$。

题解

刚开始做的时候想到直接DP,结果发现是不太行的。

要使得两点距离的最大值最小,可以二分答案 $mid$。

那么就只需判断所有可能的情况中,是否存在一种方案使得任意两点的距离 $\le mid$。

这样子就可以DP了,设 $f_{i,j}$ 表示以 $i$ 为根的子树中,满足直径 $\le mid$,用了 $j$ 个 $a$ 时,子树内的点离点 $i$ 最大的距离的最小值。

然后 $O(nk^2)$ 转移即可。

程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())
const int N=40010;
const ll inf=4e18;
int ver[N],a[N],b[N],ne[N],head[N],tot;
inline void add(int x,int y,int _a,int _b)
{
ver[++tot]=y; a[tot]=_a; b[tot]=_b; ne[tot]=head[x]; head[x]=tot;
ver[++tot]=x; a[tot]=_a; b[tot]=_b; ne[tot]=head[y]; head[y]=tot;
}
ll f[N>>1][22],g[22],mid;
int n,k,siz[N];
void dfs(int u,int pre)
{
siz[u]=0; f[u][0]=0;
ll tmp;
for(int i=head[u],v;i;i=ne[i])
if((v=ver[i])!=pre)
{
dfs(v,u);
int l=min(siz[u],k),mi=min(k,siz[u]+siz[v])+1;
fo(j,0,mi) g[j]=inf;
fo(x,0,l)
fo(y,0,min(k-x,siz[v]))
{
if(f[u][x]+f[v][y]+a[i]<=mid) g[x+y+1]=min(g[x+y+1],max(f[u][x],f[v][y]+a[i]));
if(f[u][x]+f[v][y]+b[i]<=mid) g[x+y]=min(g[x+y],max(f[u][x],f[v][y]+b[i]));
}
fo(j,0,mi) f[u][j]=g[j];
siz[u]+=siz[v]+1;
}
}
int main()
{
CASET
{
n=read(); k=read(); tot=1;
fo(i,1,n) head[i]=0;
int x,y,_a,_b;
fo(i,2,n)
{
x=read(),y=read(),_a=read(),_b=read();
add(x,y,_a,_b);
}
ll l=0,r=1000000000ll*n;
for(;l<=r;)
{
mid=(l+r)>>1;
dfs(1,0);
if(f[1][k]<=mid) r=mid-1; else l=mid+1;
}
printf("%lld\n",r+1);
}
return 0;
}

I. It’s All Squares

题解

显然地,我们只需考虑平行于坐标轴的矩形内的点,这个矩形最小且完全包住询问的多边形。

那么如何判断某个点是否在一个多边形里面呢?

根据计算几何那套理论,从该点向任意方向引出一条射线,该射线与多边形经过奇数次则在简单多边形内。

对于一个询问,字符串长度为 $4k$,则最多会包住 $k^2$ 个点。

$n,m$ 同阶,那么算一下发现,所有的询问最多包住 $\frac{\sum |S| n}{4}$ 个点,这是可以承受的。

于是暴力就好了。

程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())
const int N=403;
int a[N][N];
char s[200005];
bool ans[N][N];
int flag[N*N];
int n,m,q,len,tot;
int main()
{
CASET
{
n=read(); m=read(); q=read();
fo(i,1,n) fo(j,1,m) a[i][j]=read();
for(int L,R,U,D,x,y,sum;q;q--)
{
tot++;
L=401,R=0,U=0,D=401,sum=0;
x=read(); y=read(); scanf("%s",s+1);
len=strlen(s+1);
fo(i,1,len)
{
L=min(L,x); R=max(R,x);
D=min(D,y); U=max(U,y);
if(s[i]=='L') x--;
if(s[i]=='R') x++;
if(s[i]=='D') y--;
if(s[i]=='U') y++;
}
fo(i,L,R+1) fo(j,D,U+1) ans[i][j]=0;
fo(i,1,len)
{
if(s[i]=='L') ans[x][y+1]^=1,x--;
if(s[i]=='R') x++,ans[x][y+1]^=1;
if(s[i]=='D') y--;
if(s[i]=='U') y++;
}
fo(i,L+1,R)
{
bool bo=0;
fo(j,D+1,U)
{
bo^=ans[i][j];
if(bo)
if(flag[a[i][j]]!=tot) sum++,flag[a[i][j]]=tot;
}
}
printf("%d\n",sum);
}
}
return 0;
}

J. Lead of Wisdom

题意

有 $n$ 个东西,每个东西有种类 $t_i$,以及数字 $a_i,b_i,c_i,d_i$。

现在要你选出一个集合 $S$,要求这个集合里有每个种类最多有一个,满足以下式子最大:

$\large (100+\sum_{i\in S}a_i)(100+\sum_{i\in S}b_i)(100+\sum_{i\in S}c_i)(100+\sum_{i\in S}d_i)$

$T\leq 10,n\leq 50,0\le a_i,b_i,c_i,d_i \le 100$

题解

算法1

这个东西DP复杂度太高,贪心也不对。

那么就来随机算法吧。

毫无思路,简单粗暴。

我这里写的是爬山。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <bits/stdc++.h>
using namespace std;
#define FO(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define fo(i,j,k) for(int i=(j),end_i=(k);i<=end_i;i++)
#define ff(i,j,k) for(int i=(j),end_i=(k);i< end_i;i++)
#define fd(i,j,k) for(int i=(j),end_i=(k);i>=end_i;i--)
#define DEBUG(x) cerr<<#x<<"="<<x<<endl
#define all(x) (x).begin(),(x).end()
#define cle(x) memset(x,0,sizeof(x))
#define lowbit(x) ((x)&-(x))
#define ll long long
#define ull unsigned ll
#define db double
#define lb long db
#define pb push_back
#define mp make_pair
#define fi first
#define se second
inline int read()
{
int x=0; char ch=getchar(); bool f=0;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return f?-x:x;
}
#define CASET fo(___,1,read())
int k;
struct node{
ll a[4];
};
ll now[4];
vector<node> q[55];
vector<int> vec;
int p[55];
inline ll solve()
{
for(auto v:vec)
p[v]=rand()%q[v].size();
ll s[4],ans,cur,ss[4];
fo(i,0,3) s[i]=now[i];
for(auto v:vec) fo(i,0,3) s[i]+=q[v][p[v]].a[i];
ans=s[0]*s[1]*s[2]*s[3];
int tot=vec.size(),j,w;
for(int i=1,t=0;i<=2000;i++,t++)
{
if(t>=40) break;
j=vec[rand()%tot];
fo(i,0,3) ss[i]=s[i]-q[j][p[j]].a[i];
w=rand()%q[j].size();
fo(i,0,3) ss[i]+=q[j][w].a[i];
cur=ss[0]*ss[1]*ss[2]*ss[3];
if(cur>ans)
{
t=0;
ans=cur;
fo(i,0,3) s[i]=ss[i];
p[j]=w;
}
}
return ans;
}

int main()
{
int n,t,a,b,c,d;
CASET
{
n=read(); k=read();
vec.clear();
fo(i,1,k) q[i].clear();
fo(i,1,n)
{
t=read(); a=read(); b=read(); c=read(); d=read();
q[t].pb((node){a,b,c,d});
}
fo(i,0,3) now[i]=100;
fo(i,1,k)
if(q[i].size()==1)
{
fo(j,0,3) now[j]+=q[i][0].a[j];
}
else
{
if(q[i].size()>1) vec.pb(i);
}
ll ans=now[0]*now[1]*now[2]*now[3];
fo(t,1,200) ans=max(ans,solve());
printf("%lld\n",ans);
}
return 0;
}
算法2

考虑直接暴力,时间复杂度 $O(k^{\frac{n}{k}})$。

我们来分析复杂度,设 $f(x)=x^{\frac{n}{x}} (x > 0)$,我们需要求它的最大值。

对 $f(x)$ 求导,先取 $\ln$ 再 $\exp$ 就容易算了。

解得:$f’(x)=n(1-\ln x)x^2x^{\frac{n}{x}}$ 。

当 $f’(x)=0$ 时,有 $1-\ln x=0$,即 $x=e$。

当 $0<x<e$ 时,$f’(x)>0$,函数单调增。

当 $x>e$ 时,$f’(x)<0$,函数单调减。

也就是说,当 $k$ 取正整数时,$k=2,3$ 时复杂度是最大的,算一下发现这两个都能过。

于是暴力就好了。