Description
每年的1月10日是温暖节,在这一天,化身出题人的C_SUNSHINE将会给OIer们送温暖。OIer们只要在门口放上一个
仙人掌,就能在早上的某个时刻听到门外传来一声:“开门,送温暖——”作为一个萌萌哒OIer,Salroey从C_SUN
SHINE那里收到了一个令人感到温暖的问题,她想与你分享分享。有一个K维空间,每个整点上都有一个信号灯,每
个信号灯的位置都可以由K 个整数(x1,x2...xk) 表示,信号灯的颜色定义如下:
1.如果存在i满足xi=0则(x1,x2...xk) 为绿色。
2.如果对于所有i满足xi=1 则 (x1,x2...xk)为红色。
3.对于信号灯(x1,x2...xk) ,定义它的k 个前驱为恰好某一维的坐标比这个信号灯恰好少1
其余坐标都与这个信号灯相等的信号灯,即(x1,x2..xi-1,xi+1...xk) 。如果这些前驱中有偶数个红灯
则这个信号灯为绿色,否则为红色。
现在给定k 和一个k 维矩形,求矩形内部红灯数目,包括边界。
Input
第一行一个正整数t 表示数据组数,对于每组数据:
第一行一个整数k 。
第二行 2k个整数L1,L2..Lk,R1,R2...Rk 描述一个矩形的两个顶点。
T<=10,1<=k<=9,1<=Li<=Ri<=10^15
Output
对于每组数据输出一个整数表示红灯的数目,答案对998244353取模。
打表可知当且仅当 对于每个二进制位,至多有一维坐标为1 时为红色,于是可以从高位到低位进行数位dp,记录每一维坐标已确定部分与Li,Ri的关系($x=L_i || x=R_i || L_i<x<R_i$)
时间复杂度$O(T3^klog(max{R_i}))$
#include<cstdio> #include<cstring> typedef long long i64; const int P=998244353; int T,n,t; i64 l[11],r[11]; int pw3[11],ls[11],rs[11],eq[11],peq[11]; int f[55][20007],*f1,*f0; void inc(int&a,int b){b+=a-P;a=b+(b>>31&P);} void dfs(int w,int d,int S,int S2){ if(w==-1)return inc(f0[S2],f1[S]); S*=3,S2*=3; if(!peq[w]){ if(!ls[w])dfs(w-1,d,S,S2); dfs(w-1,d,S+1,S2+1+rs[w]); dfs(w-1,d,S+2,S2+2); if(!d){ dfs(w-1,1,S,S2+(ls[w]^1)*2); if(rs[w])dfs(w-1,1,S+1,S2+1); dfs(w-1,1,S+2,S2+2); } }else if(!eq[w]){ dfs(w-1,d,S,S2); if(!d)dfs(w-1,1,S,S2+1); }else if(d+rs[w]<=1)dfs(w-1,d+rs[w],S,S2); } int main(){ for(int i=pw3[0]=1;i<10;++i)pw3[i]=pw3[i-1]*3; f[51][0]=1; for(scanf("%d",&T);T;--T){ scanf("%d",&n); for(int i=0;i<n;++i)scanf("%lld",l+i),--l[i]; for(int i=0;i<n;++i)scanf("%lld",r+i),--r[i]; for(t=50;t>=0;--t){ f1=f[t+1]; memset(f0=f[t],0,sizeof(int)*pw3[n]); for(int i=0;i<n;++i){ ls[i]=l[i]>>t&1; eq[i]=!((l[i]^r[i])>>t); peq[i]=!((l[i]^r[i])>>t+1); rs[i]=r[i]>>t&1; } dfs(n-1,0,0,0); } int ans=0; for(int i=0;i<pw3[n];++i)inc(ans,f0[i]); printf("%d\n",ans); } return 0; }