【CF809C】Find a car(动态规划)

【CF809C】Find a car(动态规划)

题面

洛谷
CF
有一个无穷大的矩阵,第(i)行第(j)列的数是((i-1)xor(j-1)+1)(q)次询问,每次询问一个矩形内数小于等于(k)的数的和。

题解

询问等价于(sum_{i=l}^rsum_{j=L}^R [ioplus jle k]ioplus j)
把询问拆分成四个从(1)开始的东西,即([1..r,1..R],[1..l-1,1..R],[1..r,1..L-1],[1..l-1,1..L-1])
那么就可以大力数位(dp)了,设(f[i][0/1][0/1][0/1])表示(i)是否卡在界上,(j)是否卡在界上,(ioplus j)是否卡在界上,需要同时记录方案数和和。
大力转移一下就好了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MOD 1000000007
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int f[32][2][2][2],g[32][2][2][2];
int Calc(int L,int R,int K)
{
	if(L<0||R<0)return 0;
	memset(f,0,sizeof(f));memset(g,0,sizeof(g));f[31][0][0][0]=1;
	for(int i=30;~i;--i)
		for(int a=0;a<=1;++a)
			for(int b=0;b<=1;++b)
				for(int k=0;k<=1;++k)
				{
					if(!f[i+1][a][b][k])continue;
					for(int A=0;A<=1;++A)
						for(int B=0;B<=1;++B)
						{
							if(!a&&A&&!(L&(1<<i)))continue;
							if(!b&&B&&!(R&(1<<i)))continue;
							if(!k&&!(K&(1<<i))&&(A^B))continue;
							int na=a,nb=b,nk=k;
							if(!A&&(L&(1<<i)))na|=1;
							if(!B&&(R&(1<<i)))nb|=1;
							if(!(A^B)&&(K&(1<<i)))nk|=1;
							add(f[i][na][nb][nk],f[i+1][a][b][k]);
							add(g[i][na][nb][nk],g[i+1][a][b][k]);
							if(A^B)add(g[i][na][nb][nk],1ll*(1<<i)*f[i+1][a][b][k]%MOD);
						}
				}
	int ret=0;
	for(int a=0;a<=1;++a)
		for(int b=0;b<=1;++b)
			for(int k=0;k<=1;++k)
				add(ret,g[0][a][b][k]),add(ret,f[0][a][b][k]);
	return ret;
}
int main()
{
	int Q=read();
	while(Q--)
	{
		int x1=read()-1,x2=read()-1,y1=read()-1,y2=read()-1,k=read()-1;
		int ans1=(Calc(y1,y2,k)+Calc(x1-1,x2-1,k))%MOD;
		int ans2=(Calc(x1-1,y2,k)+Calc(y1,x2-1,k))%MOD;
		int ans=(ans1+MOD-ans2)%MOD;
		printf("%d
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/cjyyb/p/10473561.html