一眼看過去沒什麼思路…
先打一個(這裏)的表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
2 1 4 3 6 5 8 7 10 9 12 11 14 13 16 15
3 4 1 2 7 8 5 6 11 12 9 10 15 16 13 14
4 3 2 1 8 7 6 5 12 11 10 9 16 15 14 13
5 6 7 8 1 2 3 4 13 14 15 16 9 10 11 12
6 5 8 7 2 1 4 3 14 13 16 15 10 9 12 11
7 8 5 6 3 4 1 2 15 16 13 14 11 12 9 10
8 7 6 5 4 3 2 1 16 15 14 13 12 11 10 9
9 10 11 12 13 14 15 16 1 2 3 4 5 6 7 8
10 9 12 11 14 13 16 15 2 1 4 3 6 5 8 7
11 12 9 10 15 16 13 14 3 4 1 2 7 8 5 6
12 11 10 9 16 15 14 13 4 3 2 1 8 7 6 5
13 14 15 16 9 10 11 12 5 6 7 8 1 2 3 4
14 13 16 15 10 9 12 11 6 5 8 7 2 1 4 3
15 16 13 14 11 12 9 10 7 8 5 6 3 4 1 2
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
好整齊!仔細觀察就會發現如果把這個矩陣平均分成四塊,我們會發現左上角的那一塊和右下角的那一塊是完全一樣的,左下角的一塊和右上角的一塊剛好是另外兩塊每個數加,而且這四塊都滿足這個性質
所以如果第一個元素我們記爲對於其中的一個元素,我們會發現當中有且僅有一個數的二進制的第位爲的時候,這個元素的值會加上,又因爲這個矩陣分成的四塊都滿足這個性質,所以可以直接把分到相應的矩陣繼續算。仔細分析就可以得出^
然後就是數位dp隨便搞搞就好了。
不打表怎麼做?(orzTJY大佬的做法)
每一個點求的是這個數所在的那一行左邊的和那一列上面的那些數的,看起來很像函數
一個點的值等於所有後繼狀態的值的,所以我們可以把一個點看做一個遊戲,他的所有後繼狀態是和
我們會發現這其實就是一個Nim遊戲!對於一個點,他其實等價於一個有兩堆石子分別有個的Nim遊戲(每次從一堆中取出任意個石子後就是後繼狀態),所以就可以算出的值,這個值就是原矩陣每個數減1
根據Nim遊戲的性質就可以得到^
然後數位dp就OK了。
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int q,x_1,y_1,x_2,y_2,k,len,a[35],b[35],c[35];
pair<int,int>dp[35][2][2][2];
int Add(int a,int b){
return a+b>=mod?a+b-mod:a+b;
}
int Minus(int a,int b){
return a<b?a-b+mod:a-b;
}
pair<int,int>operator+(pair<int,int>a,pair<int,int>b){
return make_pair(Add(a.first,b.first),Add(a.second,b.second));
}
pair<int,int>dfs(int now,int f1,int f2,int f3){
if(now==-1)
return make_pair(1,0);
if(~dp[now][f1][f2][f3].first)
return dp[now][f1][f2][f3];
pair<int,int>ret=make_pair(0,0);
for(int i=0;i<=(f1?a[now]:1);i++)
for(int j=0;j<=(f2?b[now]:1);j++)
if((i^j)<=(f3?c[now]:1)){
pair<int,int>tmp=dfs(now-1,f1&&i==a[now],f2&&j==b[now],f3&&(i^j)==c[now]);
ret=ret+tmp;
if(i^j)
ret.second=(ret.second+(1ll<<now)*tmp.first)%mod;
}
dp[now][f1][f2][f3]=ret;
return ret;
}
int calc(int x,int y,int k){
if(x<0||y<0||k<0)
return 0;
memset(dp,-1,sizeof(dp));
len=0;
while(x||y||k){
a[len]=(x&1);
b[len]=(y&1);
c[len++]=(k&1);
x>>=1;
y>>=1;
k>>=1;
}
pair<int,int>ret=dfs(len-1,1,1,1);
return Add(ret.first,ret.second);
}
int main(){
scanf("%d",&q);
while(q--){
scanf("%d%d%d%d%d",&x_1,&y_1,&x_2,&y_2,&k);
printf("%d\n",Minus(Add(calc(x_2-1,y_2-1,k-1),calc(x_1-2,y_1-2,k-1)),Add(calc(x_1-2,y_2-1,k-1),calc(x_2-1,y_1-2,k-1))));
}
return 0;
}