bzoj1863 [ZJOI2006]皇帝的烦恼
problem
给出一个长度为\(n\)的环,第\(i\)个点需要分配\(a_i\)种颜色。相邻两个点不能有相同的颜色。求最少需要多少种颜色。
solution
挺巧妙的一个\(dp\)。
显然答案具有单调性,所以我们可以先二分一个答案\(x\)。
然后用\(mn[i]\)表示第\(i\)个点与第\(1\)个点最少有多少个相同的颜色,用\(mx[i]\)表示第\(i\)个点与第一个点最多有多少个相同的颜色。
然后考虑转移,对于\(mn[i]\),肯定要让\(i-1\)与\(1\)的相同颜色尽量多,才可以使\(i\)与\(1\)相同的颜色尽量少。然后考虑总共有\(x\)中颜色,在\(1\)与\(i-1\)相同颜色尽量多的情况下,还有\(x-(a_1-a_{i-1}+mx[i-1])\)种与\(1\)不同的颜色。那就让\(i\)先用这些颜色染,不够的就要用与\(1\)相同的颜色了。所以就有\(mn[i] = max(0,a_i-(x-a_1-a_{i-1}+mx[i-1])\)
然后转移\(mx[i]\),同理,如果想让\(1\)与\(i\)的相同颜色尽量多,那么就要让\(i-1\)与\(1\)的相同颜色尽量少,\(i\)可以与\(1\)相同的部分,就是\(1\)的颜色数量减去\(1\)与\(i-1\)颜色相同的部分。所以就有\(mx[i]=min(a_i,a_1-mn[i-1])\)。
PS:\(n=1\)时应当特判!(虽然数据没有卡)
code
/*
* @Author: wxyww
* @Date: 2020-04-22 18:53:27
* @Last Modified time: 2020-04-22 19:08:17
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
typedef long long ll;
const int N = 200010;
ll read() {
ll x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1; c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar();
}
return x * f;
}
int mn[N],mx[N],n,a[N];
bool check(int x) {
mx[1] = mn[1] = a[1];
for(int i = 2;i <= n;++i) {
mn[i] = max(0,a[i] - (x - a[1] - a[i - 1] + mx[i - 1]));
mx[i] = min(a[i],a[1] - mn[i - 1]);
}
return mn[n] == 0;
}
int main() {
n = read();
int l = 0,r = 100000000;
for(int i = 1;i <= n;++i) {
a[i] = read();
l = max(l,a[i] + a[i - 1]);
}
if(n == 1) {
cout<<a[1]<<endl;return 0;
}
int ans = 0;
while(l <= r) {
int mid = (l + r) >> 1;
if(check(mid)) ans = mid,r = mid - 1;
else l = mid + 1;
}
cout<<ans;
return 0;
}
===================================================================================
该怎麼去形容为思念酝酿的痛
夜空霓虹都是我不要的繁荣 ===================================================================================