好题!难题!
题意:
给出两个区间,现在任取区间的两个数(每个区间取一个),假设第一个区间取数i,第二个区间取数j,判断满足i^j>e的所有i^j的和,其中e是给定的数。
题解:
数位dp,设计这样的状态dp[i][j][k][t] 第i位时满足条件的个数,状态不好解释直解看代码。把所有的 位数弄成2进制的形式,因为2进制只有01在处理时有一些技巧,具体看代码。
注意一个细节:如果位数的存储从1开始,在代码中移位时要将pos-1,如果从0开始存储则不用。
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #include<math.h> using namespace std; typedef long long lld; #define oo 0x3f3f3f3f const lld MOD=1000000007; #define digit 66 #define maxn 2525 struct Dp { lld cnt; lld res; Dp(){cnt=res=0;} Dp(lld cnt_,lld res_){ cnt=cnt_; res=res_; } }; Dp dp[digit][2][2][2]; int bita[digit],bitb[digit],bitc[digit]; Dp dfs(int pos,int fa,int fb,int fc) { if(pos<1) return !fc ? Dp(1,0) : Dp(0,0); //因为要大于e所以异或的最后一位必须要大于第三个范围的最后一位即:fc==0 if(dp[pos][fa][fb][fc].cnt!=-1&&dp[pos][fa][fb][fc].res!=-1) return dp[pos][fa][fb][fc]; int lasta=fa?bita[pos]:1; int lastb=fb?bitb[pos]:1; int lastc=fc?bitc[pos]:-1; Dp res=Dp(0,0); for(int i=0;i<=lasta;i++) { for(int j=0;j<=lastb;j++) { int t=i^j; if(t>=lastc) { Dp temp=dfs(pos-1,fa&&i==lasta,fb&&j==lastb,fc&&t==lastc); res.cnt=(res.cnt+temp.cnt)%MOD; res.res=((res.res+t*(1ll<<(pos-1))%MOD*temp.cnt%MOD)%MOD+temp.res)%MOD; } } } dp[pos][fa][fb][fc]=res; return res; } //转化成二进制并且返回长度 int GetBit(lld x,int a[]) { int len=0; while(x) { a[++len]=x%2; x/=2; } return len; } lld GetAns(lld a,lld b,lld c) { for(int i=0;i<digit;i++) { for(int j=0;j<2;j++) { for(int k=0;k<2;k++) { for(int t=0;t<2;t++) { dp[i][j][k][t]=Dp(-1,-1); } } } } int lena=GetBit(a,bita); int lenb=GetBit(b,bitb); int lenc=GetBit(c,bitc); int len=max(lena,max(lenb,lenc)); while(lena<len) bita[++lena]=0; while(lenb<len) bitb[++lenb]=0; while(lenc<len) bitc[++lenc]=0; return (dfs(len,1,1,1).res+MOD)%MOD; } int main() { int T; lld a,b,c,d,e; scanf("%d",&T); for(int cas=1;cas<=T;cas++) { cin>>a>>b>>c>>d>>e; lld t1=GetAns(b,d,e); lld t2=GetAns(b,c-1,e); lld t3=GetAns(a-1,d,e); lld t4=GetAns(a-1,c-1,e); printf("Case %d: ",cas); cout<<((t1-t2+MOD)%MOD-t3+t4+MOD)%MOD<<endl; } return 0; }