关于 ABC G 的时间复杂度
  • 板块学术版
  • 楼主LCat90
  • 当前回复0
  • 已保存回复0
  • 发布时间2023/11/12 00:40
  • 上次更新2023/11/12 10:12:48
查看原帖
关于 ABC G 的时间复杂度
487539
LCat90楼主2023/11/12 00:40

请问这份代码到底是 O(2nn2)O(2^nn^2) 还是 O(2nn)O(2^nn)。谢谢。

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int N = 23;
int n, c, a[N], b[N], dp[1 << 22 + 2]; 
int popcount(int x) {
	if(x == 0 or x == 1) return x;
	return popcount(x / 2) + x % 2;
}
signed main() {
	memset(dp, 0x3f, sizeof dp); 
	cin >> n >> c;
	for(int i = 1;i <= n; ++i) cin >> a[i];
	for(int i = 1;i <= n; ++i) cin >> b[i];
	dp[0] = 0;
	for(int i = 0;i < (1 << n) - 1; ++i) {
		int x = popcount(i);
		 // 接着 [1,i] 注意,可以随意选取一段 
		for(int l = 1;l <= n; ++l) {
		int sub = i, sum = c, add = 1; 
			if(!(i & (1 << (l - 1))))
			for(int k = l;k <= n; ++k) { // 连续的一段的转移 [l,r] 
				if(i & (1 << (k - 1))) break ;
				sub |= 1 << (k - 1); add = k - l + 1; 
				sum += abs(b[k] - a[x + add]); 
				dp[sub] = min(dp[sub], dp[i] + sum); 
			}
		}
	}
	cout << dp[(1 << n) - 1] - c << "\n"; // 段数 -1 刀 
	return 0;
}
/* 
假设我们第一步直接重新乱切
后面就可以 O(n) 的计算答案  
考虑状态的设计,
定义 dp{S} 表示我们现在已经确定了状态 S(s_i=1 说明 b_i 已经对应并计算)+
那些 b 的话,我们是用的 [1, i] 去填充的  
现在我们采用刷表法进行转移 
单次转移,我们就考虑一个连续段即可 
然后 i = popcount(S),即 1 的个数 
*/
2023/11/12 00:40
加载中...