1. 程式人生 > 其它 >Educational Codeforces Round 103 C - Longest Simple Cycle (思維 + 貪心)

Educational Codeforces Round 103 C - Longest Simple Cycle (思維 + 貪心)

技術標籤:思維貪心codeforces 題解c++演算法貪心思維codeforces

Longest Simple Cycle

題意

n n n 條鏈,第 i i i 條鏈上有 c [ i ] c[i] c[i] 個點, a [ i ] a[i] a[i] 為第 i i i 條鏈的頂點與第 i − 1 i-1 i1 條鏈的連線點, b [ i ] b[i] b[i] 為第i條鏈的最後一個點與第 i − 1 i-1 i1 條鏈的連線點。
找這樣的一個環,環上的每個點都只被訪問一次,問該環的最大長度為多少。

思路

反向遍歷 c [ i ] c[i] c[i]

r e s 1 res1

res1 r e s 2 res2 res2

r e s 1 res1 res1 表示 每條鏈 a [ i ] a[i] a[i] b [ i ] b[i] b[i] 之間的點的個數 定義為 向內

r e s 2 res2 res2 表示 每條鏈 a [ i ] a[i] a[i] b [ i ] b[i] b[i] 到兩個端點的點的個數 定義為 向外

a [ i ] ≠ b [ i ] a[i] \neq b[i] a[i]=b[i] 時 :

顯然可知 r e s 1 res1 res1 需要用 r e s 2 res2 res2 來更新 即只有右邊那條鏈選擇向兩個端點 這條鏈才能選擇向內

res1 = res2 + abs(a[i] - b[i]) + 1;

i = 2 i = 2 i=2 a [ i ] a[i] a[i] b [ i ] b[i] b[i] 表示第2條鏈連在第一條鏈的位置 顯然不能取向外的 因為這樣形成不了環 只能取向內的情況

所以有

if (i != 2)
				res2 += c[i - 1] - abs(a[i] - b[i]) - 1 + 2;
			else res2 = res1;

a [ i ] = b [ i ] a[i] = b[i] a[i]=b[i] 時形成了環 為什麼 r e s 2 + = 1 res2 += 1

res2+=1呢 因為 第 i i i 條鏈才能在第 i + 1 i + 1 i+1 取了向外的操作下 才能取向內的操作 a [ i ] = b [ i ] a[i] = b[i] a[i]=b[i] 可以看作只能向內取

所以有

else {
		res2 += 1;
		maxn = max(maxn, res2);
		if (i != 2)res2 = c[i - 1];
	}

需要注意的是:

if (res2 < c[i - 1] && i != 2)
	res2 = c[i - 1];

可以把還未形成的環看成兩部分 一部分是 r e s 2 res2 res2 表示的上一條鏈取向外操作下的 “環” (此時還未形成環) 一部分(左半邊)還未形成 右邊的環對左邊未找到的環的大小無影響 當 r e s 2 < c [ i − 1 ] res2 < c[i - 1] res2<c[i1] 時顯然把 第 i − 1 i - 1 i1 條鏈全部當作環的右半部分更優

程式碼

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define mod 1000000007
using namespace std;

typedef long long LL;
typedef pair<int, int>PII;
inline LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }

const int N = 100010;
LL a[N], b[N], c[N];

void solve() {
	int n; cin >> n;
	
	for (int i = 1; i <= n; ++i)scanf("%lld", &c[i]);
	for (int i = 1; i <= n; ++i)scanf("%lld", &a[i]);
	for (int i = 1; i <= n; ++i)scanf("%lld", &b[i]);

	LL res1 = 0; //向內
	LL res2 = 0; //向外
	LL maxn = -INF;
	res1 = c[n], res2 = c[n];

	for (int i = n; i >= 2; --i) {
		if (a[i] != b[i]) {
			res1 = res2 + abs(a[i] - b[i]) + 1;

			if (i != 2)
				res2 += c[i - 1] - abs(a[i] - b[i]) - 1 + 2;
			else res2 = res1;

			maxn = max(maxn, max(res1, res2));
			if (res2 < c[i - 1] && i != 2)
				res2 = c[i - 1];
		}
		else {
			res2 += 1;
			maxn = max(maxn, res2);
			if (i != 2)res2 = c[i - 1];
		}
	}

	cout << maxn << endl;
}

int main() {
	int t; cin >> t;
	while (t--)
		solve();

	return 0;
}