1. 程式人生 > >【計數原理】【UVA11538】 Chess Queen

【計數原理】【UVA11538】 Chess Queen

put typename return col nbsp 題意 putchar cst putc

傳送門

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,\n,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)的呢= =

【計數原理】【UVA11538】 Chess Queen