Mutual Training for Wannafly Union #6 [SPOJ

来源:互联网 发布:知乎如何挑选钻戒 编辑:程序博客网 时间:2024/04/29 04:12

D - Matrices with XOR property

 SPOJ - VECTAR1

Imagine A is a NxM matrix with two basic properties


1) Each element in the matrix is distinct and lies in the range of 1<=A[i][j]<=(N*M)

2) For any two cells of the matrix, (i1,j1) and (i2,j2), if (i1^j1) > (i2^j2) then A[i1][j1] > A[i2][j2] ,where 

1 ≤ i1,i2 ≤ N

1 ≤ j1,j2 ≤ M.

^ is Bitwise XOR


Given N and M , you have to calculatethe total number of matrices of size N x M which have both the properties

mentioned above.  


Input format:

First line contains T, the number of test cases. 2*T lines follow with N on the first line and M on the second, representing the number of rows and columns respectively.


Output format:

Output the total number of such matrices of size N x M. Since, this answer can be large, output it modulo 10^9+7


Constraints:

1 ≤ N,M,T ≤ 1000


SAMPLE INPUT 

1

2

2

SAMPLE OUTPUT 

4

Explanation

The four possible matrices are:

[1 3] | [2 3] | [1 4] | [2 4]

[4 2] | [4 1] | [3 2] | [3 1]

题意:
给你一个n*m的矩阵,要求我们在每个格子上填数字,填数字规则为:
1、每个格子的数字必需不一样,且所填数字必需在1~n*m之间
2、任意两个个格子A[ i1 ][ j1 ]、A[ i2 ][ j2 ],若i1^j1>i2^j2,那么A[ i1 ][ j1 ]>A[ i2 ][ j2 ]
问有多少种解决方案。

一开始打了个10*10的i^j表,除了发现一些对称性质外并没有什么特别的发现。在想是不是有什么规律呢。。。首先肯定大的数字是往大的异或值里填,而异或值相同的格子可以来个全排列。于是用最笨的方法做了超时。。就不干了。。。
接下来题解q巨他们说用数位dp来做,有个热心观众冒出来说用二维线段树离线处理。。。呃呃呃呃啊为啥比赛时我就没有继续尝试呢。。可惜。。

统计在n*m中有多少个i^j = k(其中k的取值是0~1023,1000内的异或值)。那么如何上线段树呢?
首先做离线处理,讲每一个k值在最大数据范围1000的矩阵中标记出现的位置,同时将输入的的询问记录下来。接下来枚举k值,对于每一个k值更新该值的树状数组中的值,然后对每一个输入的询问记录下该k值在n*m的矩阵中有多少个。然后清空树状数组进入下一个k值的记录。
这样就离线地将所有答案都处理好了,输出的时候只要对于每个询问将所有k值的个数全排列后相乘即可,注意开longlong
还是要感谢群里大佬解答啊
代码:
#include <iostream>#include <cstring>#include <cstdio>#include <cmath>#include <vector>#include <queue>#include <algorithm>#include <map>using namespace std;const int maxn = 1030;const int mod = 1e9+7;int save[maxn][maxn];long long A[maxn];int t;map<int,int> judge;vector<pair<int,int> > rigi[maxn];struct unit{    pair<int,int> ask;    long long res[maxn];}in[maxn];int lowbit(int x) {    return x & (-x);}void update(int x,int y, int val) {    for(int i = x; i <= maxn; i += lowbit(i)) {        for(int j = y; j <= maxn; j += lowbit(j)) {            save[i][j] += val;        }    }}int query(int x, int y) {    int sum = 0;    for(int i = x; i > 0; i -= lowbit(i)) {        for(int j = y; j > 0; j -= lowbit(j)) {            sum += save[i][j];        }    }    return sum;}void init(){    int i,j,n,m;    for(i=1;i<=1000;i++){        for(j=1;j<=1000;j++){            rigi[i^j].push_back(make_pair(i, j));        }    }    memset(save, 0, sizeof(save));    for(i=1;i<=t;i++){        scanf("%d%d",&n,&m);        in[i].ask = make_pair(n, m);        for(j=0;j<=1023;j++){            in[i].res[j] = 0;        }    }    for(i=0;i<=1023;i++){        for(j=0;j<rigi[i].size();j++){            update(rigi[i][j].first, rigi[i][j].second, 1);        }        for(j=1;j<=t;j++){            in[j].res[i] = query(in[j].ask.first, in[j].ask.second);        }        for(j=0;j<rigi[i].size();j++){            update(rigi[i][j].first, rigi[i][j].second, -1);        }    }    A[0] = 1;    A[1] = 1;    for(i=2;i<=1023;i++){        A[i] = (A[i-1]*i)%mod;    }}int main(){    int i,j;    scanf("%d",&t);    long long res;    init();    for(i=1;i<=t;i++){        res = 1;        for(j=0;j<=1023;j++){            res = (res*A[in[i].res[j]])%mod;        }        printf("%lld\n",res);    }    return 0;}












0 0