西雅图
18:14发布
西雅图
18:14发布
8°
东南风 4级
空气质量 无
相对湿度 90%
今天
中雨
6°/11°
周四
中雨
3°/10°
周五
2°/10°

UVA1489/POJ3986/HDU3693 Math teacher's homework

我的blog

POJ题目链接:POJ3986 Math teacher's homework

HDU题目链接:HDU3693 Math teacher's homework

preface

本文版权归博客园,洛谷博客和蒟蒻wjr所有,欢迎转载,但需保留此段声明,并给出原文链接,如有侵权行为,还请不吝啬向博主举报,谢谢合作。

UVA评测了我半个小时,害的我猛然发现HDUPOJ上有这道题就过了

被强制要求写题解QaQ

description

给出两个整数Kn 和一个整数序列M1,M2,M3....Mn

求满足X1X2X3...Xn=K0XiMi(i=1..n)的解的个数。

solution

这题真的不好想

K移到左边得到:

X1X2X3...XnK=0

显然我们就是求与K异或等于0的方案数

先将每个Mi+1,题目就转化为:

求满足X1X2X3...XnK=00Xi<Mi(i=1..n)的解的个数。

先把这道题简单化:

有一个 n 个数的数列k,对于任意的1in满足ki{0,1}。如果k1k2k3...kn=u,且u{0,1},求满足条件的k数列的数目。

这个的答案显然是2n1。我们先随便取n1个数,最后一个数显然有且只有一种取法使得条件满足。

现在我们继续增加一个条件。如果对于一个整数0pnk数列的前p项都是确定的。这时的答案是多少?

这就不用说了。如果pn,显然是2np1;如果p=n,就得看条件满足与否了。

由以上的两个分析我们可以想到这个题的一个初步做法。

(懒人盗图)

浅蓝色的部分表示和mi的这一位一样。绿色部分表示mi的这一位是1,而这里是0的一位,橘黄色的部分表示不可以被随便确定的位子

解释一下:

蓝色部分之所以可以随意使用是因为前面决策已经设计到这里且自己做出的决策也大于这一位(这就是我们+1的原因),显然根据我们刚刚给出的结论,设浅蓝色个数位cnt,是前面的数的方案数×2cnt

而橘黄色的部分之所以不能变动是因为刚扩展的位数还不清楚接下来有没有下一个数满足有这一位数,其实我们在下一个数处理就行,不影响答案。

浅绿色部分很明显是扩展到的位数

非正解(正解是这个的优化)

dp[pos][val][len]表示当前决策到第pos个数,决策的异或值为val,最低位到len(同样也可以理解为0len1是蓝色部分)

resMpos的前缀(这里的前缀的意思是指二进制下从高位到低位的前若干个数组合成的数,但是res不能等于Mpos)

显然根据之前给出的结论

可以得出以下转移

jres中二进制下的1所在的最低位在Mpos中出现的位置的下一个1出现的位置
(绕口)

dp[pos][val][len]=(dp[pos+1][valres][max(len,j)]×2j)

(显然这么算j从0,不然按照之前得出的结论,得1)

解释一下这个dp:

  • 转移到pos+1这是数位dp固有的转移
  • 我们假设Mpos部分中的res已经被确定了,显然我们必须传到下面一位是valres
  • 显然最低肯操控的位数在绿色哪位,也就是max(len,j)
  • 根据我们之前得出的结论,我们需要让数相乘,显然,下一个数的贡献已经被算出来,根据之前问题所得出来的结论显然是×2j

显然数组开不下QwQ

正解

正解是上一个非正解的dp优化

根据打表可以发现,在poslen确定时,val除了第len位都是可以确定的

证明

根据len的转移和之前j的定义,我们可以得出len是所有决策前缀的最低位的在原数所出现的位置下一个1出现的位置的最大值,显然每个数在算上各自j那一位都有至少匹配到这里的前缀。而不包括这一位因为各自的j显然都len,所以最高位到len+1位是肯定确定的我们只需要判断第len位的异或值即可

数组终于能装的下了,时间复杂度肯定过了,是

O(312×2n)

code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define re register
#define ll long long
#define mod 1000000003
using namespace std;
template<typename T>
inline void read(T&x)
{
	x=0;
	char s=(char)getchar();
	bool f=false;
	while(!(s>='0'&&s<='9'))
	{
		if(s=='-')
			f=true;
		s=(char)getchar();
	}
	while(s>='0'&&s<='9')
	{
		x=(x<<1)+(x<<3)+s-'0';
		s=(char)getchar();
	}
	if(f)
		x=(~x)+1;
}
ll dp[55][35][2],power[35];
unsigned int a[55];
int n,k;
inline ll dfs(int pos,int val,int len)
{
	val&=(~((1<<len)-1));//把0~len-1位的数清零
	if(pos==n+1)
		return !val;
	bool flag=(val>>len)&1;
	ll &ans=dp[pos][len][flag];
	if(ans!=-1)
		return ans;
	ans=0ll;
	int res=0;
	for(re int i=31; i>=0; --i)
		if((a[pos]>>i)&1)
		{
			(ans+=dfs(pos+1,val^res,max(len,i))*power[min(len,i)]%mod)%=mod;
			res|=(1<<i);
//			printf("%d ",res);
		}
//	printf("dp[%d][%d][%d][%d]=%lld\n",pos,val,len,ans);
//	putchar('\n');
	return ans;
}
inline void work()
{
	for(re int i=1; i<=n; ++i)
	{
		read(a[i]);
		++a[i];
	}
	memset(dp,-1,sizeof(dp));
	printf("%lld\n",dfs(1,k,0));
}
int main()
{
	power[0]=1;
	for(re int i=1; i<=31; ++i)
		power[i]=(power[i-1]<<1)%mod;
//	for(re int i=0; i^31; ++i)
//		printf("%lld\n",power[i]);
	while(read(n),read(k),n||k)
		work();
}

作者:蒟蒻wjr
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

posted @   蒟蒻wjr  阅读(325)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?

点击右上角即可分享
微信分享提示