T1


很简短,也很好做,第一题直接场切。
我的方法
首先要明确一件事:就是如果选了 a x , y a_{x,y} ax,y,那么就必然要选 a y , x a_{y,x} ay,x,所以第一步就在 a x , y a_{x,y} ax,y 的基础上加上 a y , x a_{y,x} ay,x。
然后我们把每个数看做一个点,任意两个点之间都建一条边(假想的),那么选集合就相当于在跑团,而每条边的权值就是 a a a,然后就把最大团问题改编一下就行了。
代码:
#include<bits/stdc++.h>
#define int long long
#define code using
#define by namespace
#define plh std
code by plh;
int c,t,n,ed,ans,a[26][26],vis[26];
void dfs(int x,int l)
{
if(x>n)
{
ans=max(ans,l);
return;
}
int t=0;
for(int i=1;i<x;i++)
{
if(vis[i])
{
t+=a[i][x];
}
}
vis[x]=1;
dfs(x+1,l+t);
vis[x]=0;
dfs(x+1,l);
}
signed main()
{
// freopen("party.in","r",stdin);
// freopen("party.out","w",stdout);
cin>>c>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<i;j++)
{
int t=a[j][i]+a[i][j];
a[i][j]=a[j][i]=t;
ans=max(a[i][j],ans);
}
}
dfs(1,0);
cout<<ans<<endl;
ans=-2e6;
}
return 0;
}
正解
看到 n ≤ 20 n\le20 n≤20,你想到了什么?
对了,状压 DP 啊!(虽然我在比赛的时候忘了还有 lowbit 这个东西然后写出了一个 O ( 2 n n 2 ) O(2^nn^2) O(2nn2) 的状压……)
首先定义状态:这一目了然了嘛,就是 d p s dp_s dps( s s s 表示当前的状态),其中 1 1 1 表示这个数被选进集合了, 0 0 0 表示没有。
接着就是写状态转移方程,如果我们直接转移,那就会是 O ( 2 n n 2 ) O(2^nn^2) O(2nn2)(外层枚举状态 O ( n 2 ) O(n^2) O(n2),中间枚举加入集合的点 O ( n ) O(n) O(n),内层枚举集合内原本所含有的数与新的数所能构成的距离和 O ( n ) O(n) O(n)),明显只要是个正常的状压都会 TLE 的好吧,于是我们考虑优化。因为 O ( 2 n ) O(2^n) O(2n) 是肯定没法优化的,因此考虑优化一个 O ( n ) O(n) O(n)。
明显,中间那一层枚举要加入的点可以直接优化成 O ( 1 ) O(1) O(1),因为枚举这一层实际上就是在找一个基准来计算,而这个基准又是随机的,因此我们可以直接固定下来:固定成 lowbit ( s ) \operatorname{lowbit}(s) lowbit(s)(不知道 lowbit \operatorname{lowbit} lowbit 的同学自己去找资料看看)。于是时间复杂度就被我们优化成了 O ( 2 n n ) O(2^nn) O(2nn)。
但是简单一算就会发现:按照这个时间复杂度写时间复杂度就飙升到 200000000 200000000 200000000 左右了!还是过不了,于是再考虑优化。
我们先写出当前的状态转移方程:
d p s = d p s ⊕ lowbit ( s ) + a dp_s=dp_{s\oplus\operatorname{lowbit}(s)}+a dps=dps⊕lowbit(s)+a
后面那个 a a a 就表示 lowbit ( s ) \operatorname{lowbit}(s) lowbit(s) 到每个点的距离和。
很明显,要想再优化,就要把这个 a a a 预处理出来。
那有没有一种办法,让我们能预处理出 a a a 呢?啊,有的兄弟,有的。
我们设一个新的 DP: s u m s sum_s sums,表示在 s s s 这个状态下 lowbit ( s ) \operatorname{lowbit}(s) lowbit(s) 到 s s s 中的每一个点的距离和,于是我们就可以把这个状态转移方程改进一下:
d p s = d p s ⊕ lowbit ( s ) + s u m s dp_s=dp_{s\oplus\operatorname{lowbit}(s)}+sum_s dps=dps⊕lowbit(s)+sums
现在就诞生了一个新的问题: s u m s sum_s sums 怎么求?
如果直接求,我们会发现时间复杂度来到了 O ( 2 n n ) O(2^nn) O(2nn)(外面枚举状态,里面枚举 lowbit ( s ) \operatorname{lowbit}(s) lowbit(s) 到每个点的距离和),仔细观察容易发现:这个 DP 所需要的循环和上面的 DP 所需要的循环很类似。那我们就采用相同的方法:把动点固定成定点。而 lowbit ( s ) \operatorname{lowbit}(s) lowbit(s) 已经被用过了,因此我们换个特殊点:最大的点。我们记做 upbit ( s ) \operatorname{upbit}(s) upbit(s) 吧。
于是我们就可以写出状态转移方程:
s u m s = s u m s ⊕ upbit ( s ) + g lowbit ( s ) , upbit ( s ) sum_s=sum_{s\oplus\operatorname{upbit}(s)}+g_{\operatorname{lowbit}(s),\operatorname{upbit}(s)} sums=sums⊕upbit(s)+glowbit(s),upbit(s)
其中 g g g 表示题中输入的那个数组。
然后就可以快乐的写代码了!
我绝对不会告诉你我没写。
T2


考试时:不是 k ≤ 120 k\le120 k≤120 是什么鬼!?还有那个 n ≤ 1 0 36 n\le10^{36} n≤1036 是什么!?这是要弄死人的节奏吗!?
为了您能更好的理解这道题是如何被一步一步想出来的,我们一个数据点一个数据点的讲:
Subtask 1
很简单,翻译下来就是 x − y = n x-y=n x−y=n,令 y = 1 y=1 y=1,于是 x = n + 1 x=n+1 x=n+1,然后直接输出即可。注意题目中说了 x , y ≤ 1 0 36 x,y\le10^{36} x,y≤1036。
Subtask 2
翻译一下就是 x 2 − y 2 = ( x + y ) ( x − y ) = n x^2-y^2=(x+y)(x-y)=n x2−y2=(x+y)(x−y)=n,现在设 a = x + y , b = x − y a=x+y,b=x-y a=x+y,b=x−y,则 x = a + b 2 , y = a − b 2 x=\cfrac{a+b}{2},y=\cfrac{a-b}{2} x=2a+b,

最低0.47元/天 解锁文章
1283

被折叠的 条评论
为什么被折叠?



