• 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

  • 相关阅读:
    orm添加表记录
    创建多表模型
    包的使用
    日志写法
    os模块,是通过和操作系统交互进行操作
    sys python解释器做交互
    软件开发规范
    模块 time模块 datatime模块 random模块
    装饰器
    装饰器进阶
  • 原文地址:https://www.cnblogs.com/gengchen/p/6011804.html
Copyright © 2020-2023  润新知