CSP-S模拟赛二总结(实际难度大于CSP-S)

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 n20,你想到了什么?

看这里。

对了,状压 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=dpslowbit(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=dpslowbit(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=sumsupbit(s)+glowbit(s),upbit(s)

其中 g g g 表示题中输入的那个数组。

然后就可以快乐的写代码了!

我绝对不会告诉你我没写。

T2

考试时:不是 k ≤ 120 k\le120 k120 是什么鬼!?还有那个 n ≤ 1 0 36 n\le10^{36} n1036 是什么!?这是要弄死人的节奏吗!?

为了您能更好的理解这道题是如何被一步一步想出来的,我们一个数据点一个数据点的讲:

Subtask 1

很简单,翻译下来就是 x − y = n x-y=n xy=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,y1036

Subtask 2

翻译一下就是 x 2 − y 2 = ( x + y ) ( x − y ) = n x^2-y^2=(x+y)(x-y)=n x2y2=(x+y)(xy)=n,现在设 a = x + y , b = x − y a=x+y,b=x-y a=x+y,b=xy,则 x = a + b 2 , y = a − b 2 x=\cfrac{a+b}{2},y=\cfrac{a-b}{2} x=2a+b,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值