跳转至

2020-08-19

http://icpc.upc.edu.cn/problem.php?cid=2550&pid=6

题目描述

Rainy7 一天醒来,发现自己进入了魔法世界。

一道大门矗立在 Rainy7 面前,似乎需要密码解锁。

Rainy7 经过一番查找后,找到了密码对应的问题:在n×m的棋盘上摆放两个不同颜色的皇后,使得它们能够相互攻击,总共有多少种摆法?

我们称两个皇后能够相互攻击,当且仅当它们在同一行或同一列或同一斜线上。

她只用了114514-1919810 s就解决了问题并打开了大门,于是把问题交给了您。

输入

第一行一个整数t,表示数据组数。 接下来t行,每行两个正整数n,m,表示棋盘的长和宽。

输出

t行,每行一个数,表示方案数。 由于这个数可能很大,您只要输出它对109+7取模的结果就可以了。

样例输入

【样例1】 1 2 2 【样例2】 1 114514 114514 【样例3】 2 165528 123456 132435 423153

样例输出

【样例1】 12 【样例2】 587308676 【样例3】 718509545 475373430

提示

样例1解释 如图所示:

对于20%的数据,1≤n,m≤50,1≤t≤10 对于50%的数据,1≤n,m≤300 对于70%的数据,1≤n,m≤5000 对于100%的数据,1≤n,m≤5×105,1≤t≤5000 本题部分数据卡常,请注意常数优化

解析

这道题目可以分为三种情况来讨论,横竖和对角线,横和竖都比较简单,结果为n*m*(n+m-2),对角线上推到见下图: 在这里插入图片描述

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll n,m;
ll mul(ll a,ll b)
{
    ll sum1=0;
    ll sum2=a;
    while(b!=0)
    {
        if(b%2==1)
            sum1=(sum1+sum2)%mod;
        sum2=(sum2+sum2)%mod;
        b=b/2;
    }
    return sum1;
}
int main()
{
    ll t;
    scanf("%lld",&t);
    while(t--)
    {
        ll ans=0;
        scanf("%lld%lld",&n,&m);
        if(n>m)
            swap(n,m);
        ans+=mul(n*m,n+m-2);
        ll k1=n*(n-1)*2;
        ll k2=3*m-n-1;
        if(k1%3==0)
            k1=k1/3;
        else if(k2%3==0)
            k2=k2/3;
        ans+=mul(k1,k2);
        printf("%lld\n",ans%mod);
    }
    return 0;
}