ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CCPC2019 Harbin Site B.Binary Numbers

2021-11-09 21:03:29  阅读:172  来源: 互联网

标签:CCPC2019 LCP int ll Site lst Numbers dp define


传送门


题面挺不好懂,简单来说就是有\(0 \sim 2^m-1\)个数被划分成了\(n\)段,从每一段中选出一个数\(a_i\),要满足题中的限制。而一种\(\{a_i\}\)选择方案的价值是这\(n\)个数的乘积,问所有合法的方案的价值之和对\(100000007\)取模的结果。


首先关于题目中的函数\(F_m(a,b)\),其实就是\(a,b\)二进制表示下的最长公共前缀(把最高位看成第一位)。而这个函数实际上是一个单峰函数,即对于\(F_m(a,b)\)来说,当\(b < a\)时,\(b\)越小,\(LCP(a,b)\)越短;当\(b > a\)时,\(b\)越大,\(LCP(a,b)\)越小。

那么如果要满足题中的限制,对于每个区间需要满足:

  1. \(LCP(a_i,l_i)\geqslant LCP(a_{i-1},l_i)\),
  2. \(LCP(a_i,r_i)\geqslant LCP(a_{i+1},r_i)\).

可以采用动态规划,状态还是比较巧妙的:令\(dp[i][j][k]\)表示到第\(i\)个区间,\(LCP(a_i,l_{i+1})=j,LCP(a_i,r_i)=k\)时的贡献和。枚举\(a_i\),考虑如何从\(dp[i-1]\)转移到\(dp[i]\):记上一层的状态为\(dp[i-1][j_{lst}][k_{lst}]\),这一维的状态为\(dp[i][j_{now}][k_{now}]\),那么\(j_{lst} \in [0,LCP(a_i,l_i)],k_{lst} \in [LCP(a_i,r_{i-1}),m]\),这个区间中的\(j_{lst}\)和\(k_{lst}\)都可以转移到\(j_{now}\)和\(k_{now}\),乘上位权\(a_i\)即可.

这样时间复杂度是\(O(2^m m^2)\).

#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 ll mod = 100000007;
const int maxn = (1 << 17) + 5;
const int maxm = 18;
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 ll ADD(ll a, ll b) {return a + b < mod ? a + b : a + b - mod;}

int n, m, l[maxn], r[maxn];

In int lcp(int a, int b)
{
	for(int i = m - 1; i >= 0; --i)
		if(((a >> i) & 1) ^ ((b >> i) & 1)) return m - i;
	return m;
}

ll dp[maxn][maxm][maxm];
In ll solve()
{
	for(int i = 0; i <= n; ++i)
		for(int j = 0; j <= m; ++j) fill(dp[i][j], dp[i][j] + m + 1, 0);
	dp[0][0][m] = 1;
	for(int i = 1; i <= n; ++i)
	{
		for(int x = l[i]; x <= r[i]; ++x)
		{
			int lstl = lcp(x, l[i]), lstr = lcp(x, r[i - 1]);
			int nowl = i == n ? 0 : lcp(x, l[i + 1]);
			int nowr = lcp(x, r[i]);
			for(int j = 0; j <= lstl; ++j)
				for(int k = lstr; k <= m; ++k)
					dp[i][nowl][nowr] = ADD(dp[i][nowl][nowr], dp[i - 1][j][k] * x % mod);
		}
	}
	ll ans = 0;
	for(int j = 0; j <= m; ++j)
		for(int k = 0; k <= m; ++k) ans = ADD(ans, dp[n][j][k]);
	return ans;
}

int main()
{
	int T = read();
	while(T--)
	{
		m = read(), n = read();
		for(int i = 1; i <= n; ++i) l[i] = read(), r[i] = read();
		write(solve()), enter;
	}
	return 0;
}

标签:CCPC2019,LCP,int,ll,Site,lst,Numbers,dp,define
来源: https://www.cnblogs.com/mrclr/p/15530878.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有