SPOJ - VECTAR1 Matrices with XOR property

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,代表矩阵的大小,如果矩阵中上任何一个坐标异或值大于另一个坐标时,这个位置上的值也大于另一个位置上的值时就符合是条件,并且矩阵上所有的点都是<=n*m的

我们可以知道所有的坐标x,y对称的点它们的异或值是0,那么主对角线上所有坐标异或都是0,根据题意,他们就必须是1~N*M中最小的几个数,比如4*4的矩阵他们就得是1,2,3,4,而与对角线对称的所有坐标异或也肯定是相同的,比如4*4矩阵中的3,4与4,3异或值最大是7,我们把他俩归属为第一梯队,这俩位置上的值只能是15和16,当然他俩可以互换位置,也就是要全排列,那么接下来那些异或值小的坐标就是下一梯队,比如2,4与4,2是13,14两个数。最后一个梯队肯定是主对角线的坐标因为异或值都是0。当然当一个矩阵很大肯定会出现很多个坐标异或值相同,只要异或值相同他们就属于一个梯队,这个梯队内的值就要全排列。最后科普一个知识。

2的次方有:1,,2,4,8,16,32,64,128,256,512,1024。最后一个就是2^10。任何一个数前几项和都是这个数-1,比如:64的前几项和是1+2+4+8+16+32=63。

异或是基于2进制的运算,想一下异或的规则,我上边写的是2的次方换成2进制就是1,10,100,1000.....10000000000。那么我们就知道1000肯定在1024也就是2^10之内的,然后异或值要最大肯定是想要每位全是1,那么1024是10000000000,那么1024-1的异或值就是每位全是1 的值。也可以理解为1+10+100+...+1000000000。那么1000以内异或值肯定1023够了

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<algorithm>
#define inf 0x3f3f3f3f
#define ll long long
#define maxx 5000000
using namespace std;
const ll mod=1e9+7;
int mapp[1000005];
ll a[1000005];
int main()
{
    int t,n,m;
    scanf("%d",&t);
    memset(a,0,sizeof(a));
    a[0]=1;
    for(int i=1;i<=1000000;i++)
        a[i]=(a[i-1]*i)%mod;
    while(t--)
    {
        memset(mapp,0,sizeof(mapp));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                mapp[i^j]++;
        }
        ll ans=1;
        for(int i=0;i<=1023;i++)
        {
            ans=(ans*a[mapp[i]])%mod;
        }
        printf("%lld\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值