20180516模拟赛T1——queen

题解

这题显然是\(总方案数不可行方案数总方案数-不可行方案数\)(直接算是无规则的)。总方案数是\(n^2m^2\),于是问题就在于不可行的方案数。

若queen落在一个点上,则横竖是十分好求的(\(n+m\)),如果能求出斜的两条就完美了。

我们发现,这种方法Q的位置会加三次,于是我们可以在最后统一减\(3nm\)

然后比较困难的是求斜的边。

假定我们求从左上到右下线的总长度。钦定\(n\le m\)。于是就得到这样一张图:

绿色区域的点和竖线是等效的,主要是白色区域。

对于每一条斜线,我们发现第\(i\)线上的点的个数是\(i\),于是我们就可以很容易地得出不可行方案数的总和为,\(\sum_{i=1}^n i^2\)有于有4块(反着还有两块),故要乘4。

于是就是要快速求出\(\sum_{i=1}^n i^2\)。。\(\sum_{i=1}^n i^2 = \frac{n(n+1)(2n+1)}{6}\)由于我太菜了,只会归纳法,本想看一下如何现场手推(想看如何现场推的可以点这里)。

于是最后就是高精的问题了,可以不压位。

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int width = 4;
const int mod = 1e4;

typedef long long LL;

struct HugeInt
{
    int a[50];
    int len;

    inline void clear()
    {
        memset(a, 0, sizeof(a));
        len = 0;
    }
};

HugeInt operator + (HugeInt a, HugeInt b)
{
    HugeInt c;
    c.clear();
    int maxlen = max(a.len, b.len);
    for(int i = 0; i < maxlen; ++i)
    {
        c.a[i] += a.a[i]+b.a[i];
        c.a[i+1] += c.a[i]/mod;
        c.a[i] %= mod;
    }
    c.len = maxlen;
    while(c.a[c.len])
        c.len++;
    return c;
}

HugeInt operator - (HugeInt a, HugeInt b)
{
    HugeInt c;
    c.clear();
    c.len = a.len;
    for(int i = 0; i < c.len; ++i)
    {
        c.a[i] += a.a[i]-b.a[i];
        if(c.a[i]<0)
        {
            a.a[i+1]--;
            c.a[i] += mod;
        }
    }
    while(!c.a[c.len-1] && c.len>=1)
        c.len--;
    return c;
}

HugeInt operator * (HugeInt a, HugeInt b)
{
    HugeInt c;
    c.clear();
    for(int i = 0; i < a.len; ++i)
        for(int j = 0; j < b.len; ++j)
            c.a[i+j] += a.a[i] * b.a[j];
    c.len = a.len + b.len - 1;
    for(int i = 0; i < c.len; ++i)
    {
        c.a[i+1] += c.a[i]/mod;
        c.a[i] %= mod;
    }
    while(c.a[c.len])
        c.len++;
    return c;
}

bool operator < (HugeInt a, HugeInt b)
{
    if(a.len != b.len)
        return a.len < b.len;
    else
    {
        for(int i = a.len-1; i >= 0; --i)
        {
            if(a.a[i] != b.a[i])
                return a.a[i] < b.a[i];
        }
    }
    return false;
}

HugeInt give(long long a)
{
    HugeInt re;
    re.clear();
    while(a)
    {
        re.a[re.len++] = a%mod;
        a /= mod;
    }
    return re;
}

HugeInt operator + (HugeInt a, LL b)
{
    return a + give(b);
}

HugeInt operator + (LL a, HugeInt b)
{
    return b + a;
}

HugeInt operator * (HugeInt a, LL b)
{
    return a * give(b);
}

HugeInt operator * (LL a, HugeInt b)
{
    return b * a;
}

HugeInt operator - (HugeInt a, LL b)
{
    return a - give(b);
}

HugeInt operator / (HugeInt a,LL b)
{
    HugeInt ans;
    ans.clear();
    ans=a;
    LL my=0;
    for(int i=ans.len-1; i>=0; i--)
    {
        ans.a[i]+=my;
        my=ans.a[i]%b*mod;
        ans.a[i]/=b;
    }
    while(!ans.a[ans.len-1])
        ans.len--;
    return ans;
}

void print(HugeInt a)
{
    printf("%d", a.a[a.len-1]);
    for(int i = a.len-2; i>=0; --i)
        printf("%04d", a.a[i]);
}

void solve(LL n, LL m)
{
    if(m < n)
        swap(n, m);
    HugeInt nn = give(n);
    HugeInt mm = give(m);
    print(nn*nn*mm*mm-(nn*(nn+1)*(nn*2+1)/3*2+nn*nn*2*(mm-nn-1)+(nn+mm)*nn*mm-3*nn*mm));
    puts("");
}

int main()
{
    freopen("queen.in", "r", stdin);
    freopen("queen.out", "w", stdout);
    int nmn;
    long long a, b;
    scanf("%d", &nmn);
    while(nmn--)
    {
        scanf("%lld%lld", &a, &b);
        solve(a, b);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/pfypfy/p/9048209.html