• 【计数原理】【UVA11538】 Chess Queen


    传送门

    Description

      给你一个n*m的棋盘,在棋盘上放置一黑一白两个皇后,求两个皇后能够互相攻击的方案个数

    Input

      多组数据,每组数据包括:

    • 一行,为n和m

      输入结束标志为n=m=0。

    Output

      对于每组数据,输出:

    • 对应的放置方案数

    Sample Input

    2 2
    100 223
    2300 1000
    0 0

    Sample Output

    12
    10907100
    11514134000

    Hint

    n,m≤1e6,n和m不全为1。保证最终答案在long long int范围之内

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

    黑白两个皇后位置相反算两种不同的方案。

    Solution

      考虑两个皇后相互攻击的情况,显然相互之间没有包含关系,故而可以使用加法原理,分别求出方案数后相加。

      对于在同一列上的方案数,设这个棋盘是m行n列的,不妨设n≤m,先考虑放置一只皇后,那么对于这n列,每一列都有m种放置方法,即共有n*m种放置方法。再考虑放置另一个皇后,对于每一种方案,两个皇后相互攻击当且仅当后放的皇后在先放的皇后的那一列上的除先放的皇后所在位置之外的m-1个位置上。也就是对于每种放置第一只皇后的方案共有m-1个满足题意的方案。使用乘法原理,那么在同一列上的方案数就是n*m*(m-1)。

      同理易得,在同一行上的方案数是n*m*(n-1)。

      对角线上的元素同理。不同的是,对于一个n*m的棋盘,不妨设n≤m,其对角线长度如下:

      1,2,3,……n,n,n,……,3,2,1。其中共有(m-n+1)个n。

      只考虑一条斜线,那么这样的方案数就是(∑(i:1 to n-1) i*(i-1)) + n*(m-n+1)*(n-1)。化简这个式子。以下省略sigma后i的范围

      ∑i*(i-1)=∑i2-∑i。其中∑i=n(n-1)/2。对于∑i2,有如下结论:

      n(i=1)i2 = n(n+1)(2n+1)/6

      证明?能吃嘛?

      那么对于本题i∈[1,n-1],∑i2=(1/6)*n*(n-1)*(2n-4)。
      因为是两条对角线,所以需要×2。带入方案数的式子,斜线上的方案数就是

      2n(n-1)(3m-n-1)/3。

      将上面几种情况相加即得答案

    Code  

    #include<cstdio>
    #define rg register
    #define ci const int
    #define LL unsigned long long int
    
    namespace IO {
        char buf[50];
    }
    
    inline void qr(LL &x) {
        char ch=getchar(),lst=' ';
        while(ch>'9'||ch<'0') lst=ch,ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        if (lst=='-') x=-x;
    }
    
    inline void write(LL x,const char aft,const bool pt) {
        if(x<0) {putchar('-');x=-x;}
        int top=0;
        do {
            IO::buf[++top]=x%10+'0';
            x/=10;
        } while(x);
        while(top) putchar(IO::buf[top--]);
        if(pt) putchar(aft);
    }
    
    template <typename T>
    inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
    template <typename T>
    inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
    template <typename T>
    inline T mabs(const T &a) {if(a<0) return -a;return a;}
    
    template <typename T>
    inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;}
    
    LL n,m;
    
    int main() {
        qr(n);qr(m);
        while(n||m) {
            if(n>m) mswap(n,m);
            write(n*m*(n-2+m)+2*n*(n-1)*(3*m-n-1)/3,'
    ',true);
            n=m=0;qr(n);qr(m);
        }
        return 0;
    }

    Summary

    1、∑n(i=1)i2 = n(n+1)(2n+1)/6

    2、看到1e6的题,如果因为答案大小限制了输入的大小,不妨往数学上想想,万一是O(1)的呢= =

  • 相关阅读:
    初识函数定义与调用 * 和 **
    文件操作
    小程序缓存数据
    调用外部的方法
    小程序订单的待付款实现倒计时(秒)
    小程序上线流程
    微信小程序点击保存图片到相册
    修改头像
    点击保存图片
    小程序的学习王战
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/9463157.html
Copyright © 2020-2023  润新知