P1371 NOI元丹

luogu月赛的题
本来想爆搜,但是经过ly大佬的点拨,明白这是一个dp。
我们定义dp[n]为从n开始的可行串的数目,具体如下:如果n为‘I',则是从n开始有多少个I,如果n为'O',既是从n开始有多少个’OI‘,如果n为’N‘,则是从n开始有多少个’NOI'
我们已经定义了状态,那么怎么转移呢?我们以n是‘N'为例,’NOI'的数目可以分为两部分:1)包括n, 2)不包括n。所以,我们可以这样计算dp[n],找到从n开始的第一个N和O,把两个字符的dp值相加,就得到了答案。
我们从后往前推,可以估算一下复杂度:状态数O(n),转移O(n),总的复杂度是O(n^2)。
对于每一个字串,我们都可以计算出其结果。所以下面的问题就是怎么去插。
首先,我们可以用链表来存储这一个字串,来优化一下常数;
第二,我们可以证明,对于N,把他插到最前面,一定是最优的,对于I,把他插到最后面,一定是最优的,
但是对于O我们还没有想出比较好的插法,目前的想法是去枚举。
这样在O(n2)的时间内,我们就可以算出。
ly大佬用这个算法得了60分。。。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200;
int n;
string str;
int cnt;
int table[maxn];
int ans[maxn];
int tmp[maxn];
//==============

int value[maxn];
int count() {
	int pos = n - 1;
	int i, j;
	if(tmp[n] == 2) value[n] = 1;
	else value[n] = 0;
	while(pos != -1) {
		if(tmp[pos] == 2) {
			for(i = pos+1; i <= n; i++) {
				if(tmp[i] == tmp[pos]) break;
			}
			value[pos] = value[i] + 1;
		}
		else if(tmp[pos] == 1) {
			for(i = pos+1; i <= n; i++) {
				if(tmp[i] == 1) break;
			}
			for(j = pos+1; j <= n; j++) {
				if(tmp[j] == 2) break;
			}
			value[pos] = value[i] + value[j];
		}
		else if(tmp[pos] == 0) {
			for(i = pos+1; i <= n; i++) {
				if(tmp[i] == 1) break;
			}
			for(j = pos+1; j <= n; j++) {
				if(tmp[j] == 0) break;
			}
			value[pos] = value[i] + value[j];
		}
		pos--;
	}
	for(i = 0; i < n; i++) {
		if(tmp[i] == 0) break;
	}
	return value[i];
}
//==============
int main(int argc, char const *argv[])
{
	cin >> n >> str;
	memset(value, 0, sizeof(value));
	for(int i = 0; i <= n;i++) {
		if(str[i] == 'N') table[i] = 0;
		else if(str[i] == 'O') table[i] = 1;
		else if(str[i] == 'I') table[i] = 2;
	}
	tmp[0] = 0;
	for(int i = 1; i <= n+1;i++) tmp[i] = table[i-1];
	int a = count();
	for(int i = 1; i <= n+1;i++) tmp[i] = table[i];
	tmp[n+1] = 2;
	int b = count();
	int i, k;
	for(k = n; k >= 0; k--) if(table[k] == '1') break;
	for(i = 0;i <= k; i++) {
		tmp[i] = table[i];
	}
	tmp[i] = 1;
	for(;i<=n;i++) {
		tmp[k] = table[k-1];
	}
	int c = count();
	cout << max(max(a, b), c);
	return 0;
}
/*void dfs(int choose, int pos) {
	if(choose == n){
	cnt++;return;}
	if(pos == str.size()) return;
	for(int i = pos; i <= str.size(); i++) {
		if(tmp[i] == choose) {
		ans[choose] = i;
		dfs(choose + 1, i+1);}
	}
}
int count() {
	cnt = 0;
	dfs(0, 0);
	return cnt;
}*/
	/*cin >> n >> str;
	int maxx = 0;
	for(int i = 0; i <= str.size();i++) {
		if(str[i] == 'N') table[i] = 0;
		else if(str[i] == 'O') table[i] = 1;
		else if(str[i] == 'I') table[i] = 2;
	}
	int k; 
	for(int i = 0; i < 3; i++) {
		for(int j = 0; j <= n; j++) {
			for(k = 0; k <= j; k++) {
				tmp[k] = table[k];
			}
			tmp[k] = i;
			for(;k<=n;k++) {
				tmp[k] = table[k-1];
			}
			maxx = max(maxx, count());
		}
	}
	cout << maxx;*/

54 NONOONIONIINIOOONONIIIINNONOINOONNOOIIOIOIOIINONNNIOON
10 ONNINNONNI

posted on 2016-10-29 21:02  蒟蒻konjac  阅读(180)  评论(0编辑  收藏  举报