zoukankan      html  css  js  c++  java
  • CF1313D Happy New Year

    传送门


    这题挺妙的,我题解都看了半天。


    题目的意思是有(n)个操作,每个操作可以让区间([L_i,R_i])的数加1,问在每个操作最多用一次的前提下,序列中奇数最多的个数。


    这么一看确实不知道怎么做,但是题中还给了一个限制,就是区间最多会重叠(k(k leqslant 8))层。这就启发我们说不定可以用状压dp。


    首先把(n)个区间拆成((L_i, 1))((R_i + 1, -1))(2n)个点,然后考虑每一段怎么怎么求。令(dp[i][S])表示从第(1)段到第(i)段,选了区间编号的集合为(S)时,奇数最多的个数。

    对于区间编号,是可以在dp的时候处理出来的,详见代码。对于第(i)段和第(i-1)段,必然只有一个区间发生了变化(对于端点重合的部分,可以看成长度为(0)的一段),假设为第(k)个区间,那么就要分两种情况:

    1. (i)段是区间(k)的开始,那么对于每一个状态(S),只要枚举是否选择区间(k)即可,转移方程详见代码吧,好理解,但不太好写;
    2. (i)段是区间(k)的结束,那么对于每一个状态(S),首先要保证第(k)位为(0),然后也是枚举这个区间之前是否选了进行转移。

    这样扫描到最后一段,所有的区间都结束了,因此答案就是(dp[2n][0]).

    时间复杂度(O(n log n + 2^k n))(nlog n)是排序复杂度。


    代码实现参考了洛谷的一篇题解,用的滚动数组。

    #include<bits/stdc++.h>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    In void MYFILE()
    {
    #ifndef mrclr
    	freopen(".in", "r", stdin);
    	freopen(".out", "w", stdout);
    #endif
    }
    
    int n, m;
    struct Node
    {
    	int pos, d;
    	In bool operator < (const Node& oth)const
    	{
    		return pos < oth.pos || (pos == oth.pos && d < oth.d);
    	}
    }t[maxn << 1];
    
    int dp[256], vis[10];
    
    int main()
    {
    //	MYFILE();
    	n = read(), read(), read(); m = n << 1; 
    	for(int i = 1; i <= n; ++i) 
    	{
    		int L = read(), R = read();
    		t[i] = (Node){L, i}, t[n + i] = (Node){R + 1, -i};
    	}
    	sort(t + 1, t + m + 1); t[m + 1].pos = t[m].pos;
    	fill(dp + 1, dp + 256, -INF);
    	for(int j = 1; j <= m; ++j)
    	{
    		int d = t[j].d, len = t[j + 1].pos - t[j].pos, k;
    		if(d > 0)
    		{
    			for(int i = 0; i < 8; ++i)
    				if(!vis[i]) {vis[k = i] = d; break;}
    			for(int i = 255; i >= 0; --i)
    				if((i >> k) & 1) dp[i] = dp[i ^ (1 << k)] + len * __builtin_parity(i);
    				else dp[i] = dp[i] + len * __builtin_parity(i);
    		}		//__builtin_pairty(i):i的二进制位如果有奇数个,返回1;否则返回0。 
    		else
    		{
    			for(int i = 0; i < 8; ++i)
    				if(vis[i] == -d) {vis[k = i] = 0; break;}
    			for(int i = 0; i < 256; ++i)
    				if((i >> k) & 1) dp[i] = -INF;
    				else dp[i] = max(dp[i], dp[i ^ (1 << k)]) + len * __builtin_parity(i);
    		}
    	}
    	write(dp[0]), enter;
    	return 0;
    }
    
  • 相关阅读:
    Windows安装深度学习框架Tensorflow GPU版本
    Genymotion3.0.4(with VirtualBox 个人免费版)安装及使用
    09.Python基础--迭代器
    08.Python基础--面向对象深入
    07.Python基础--面向对象
    06.Python基础--函数深入
    05.Python基础--函数
    04.Python基础--深入流程控制
    03.Python基础--流程控制
    02.Python基础--数据类型
  • 原文地址:https://www.cnblogs.com/mrclr/p/15330600.html
Copyright © 2011-2022 走看看