动态规划(DP计数):HDU 5116 Everlasting L

Matt loves letter L.

A point set P is (a, b)-L if and only if there exists x, y satisfying:

P = {(x, y), (x + 1, y), . . . , (x + a, y), (x, y + 1), . . . , (x, y + b)}(a, b ≥ 1)

A point set Q is good if and only if Q is an (a, b)-L set and gcd(a, b) = 1.

Matt is given a point set S. Please help him find the number of ordered pairs of sets (A, B) such that:

 

Input

The first line contains only one integer T , which indicates the number of test cases.

For each test case, the first line contains an integer N (0 ≤ N ≤ 40000), indicating the size of the point set S.

Each of the following N lines contains two integers xi, yi, indicating the i-th point in S (1 ≤ xi, yi ≤ 200). It’s guaranteed that all (xi, yi) would be distinct.
 

Output

For each test case, output a single line “Case #x: y”, where x is the case number (starting from 1) and y is the number of pairs.
 

Sample Input

2
6
1 1
1 2
2 1
3 3
3 4
4 3
9
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3

Sample Output

Case #1: 2
Case #2: 6

Hint

n the second sample, the ordered pairs of sets Matt can choose are: A = {(1, 1), (1, 2), (1, 3), (2, 1)} and B = {(2, 2), (2, 3), (3, 2)} A = {(2, 2), (2, 3), (3, 2)} and B = {(1, 1), (1, 2), (1, 3), (2, 1)} A = {(1, 1), (1, 2), (2, 1), (3, 1)} and B = {(2, 2), (2, 3), (3, 2)} A = {(2, 2), (2, 3), (3, 2)} and B = {(1, 1), (1, 2), (2, 1), (3, 1)} A = {(1, 1), (1, 2), (2, 1)} and B = {(2, 2), (2, 3), (3, 2)} A = {(2, 2), (2, 3), (3, 2)} and B = {(1, 1), (1, 2), (2, 1)} Hence, the answer is 6.
  这道题DP计数,十分有意义。
  dp[i][j]:表示a∈[1,i],b∈[1,j],sigma(a,b)==1
  sum[i][j]:表示竖直部分穿过点(i,j)的L的个数
  看代码就能懂了……
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=210;
typedef long long LL;
LL map[N][N],st[N],S,M;
LL f[N][N],dp[N][N],sum[N][N];
/*f[i][j]:[1,j]中与i互质的数的个数*/
LL dwn[N][N],rht[N][N];int T,cas,k,x,y;
LL Gcd(LL a,LL b){return b?Gcd(b,a%b):a;}
void Prepare(){
    for(int i=1;i<=200;i++)
        for(int j=1;j<=200;j++){
            f[i][j]=f[i][j-1]+(Gcd(i,j)==1);
            dp[i][j]=dp[i-1][j]+f[i][j];
        }
}
void Init(){S=M=0;
    memset(map,0,sizeof(map));
    memset(sum,0,sizeof(sum));
    memset(dwn,0,sizeof(dwn));
    memset(rht,0,sizeof(rht));
}
int main(){
    Prepare();
    scanf("%d",&T);
    while(T--){
        Init();scanf("%d",&k);
        while(k--){scanf("%d%d",&x,&y);map[x][y]=1;}
        for(int i=200;i>=1;i--)
            for(int j=200;j>=1;j--){
                if(!map[i][j])continue;
                if(map[i+1][j])dwn[i][j]=dwn[i+1][j]+1;
                if(map[i][j+1])rht[i][j]=rht[i][j+1]+1;
            }
        
        for(int i=1;i<=200;i++)
            for(int j=1;j<=200;j++){
                if(!map[i][j])continue;
                memset(st,0,sizeof(st));
                for(int k=1;k<=dwn[i][j];k++)
                    st[k]=f[k][rht[i][j]];
                for(int k=dwn[i][j];k>=1;k--)
                    st[k-1]+=st[k];
                for(int k=0;k<=dwn[i][j];k++)
                    sum[i+k][j]+=st[k];
                S+=st[0];            
            }
        
        for(int i=1;i<=200;i++)
            for(int j=1;j<=200;j++){
                if(!dwn[i][j])continue;
                if(!rht[i][j])continue;
                LL tot=dp[dwn[i][j]][rht[i][j]];
                LL calc=sum[i][j]-tot;
                for(int k=1;k<=rht[i][j];k++){
                    calc+=sum[i][j+k];
                    M+=2*calc*f[k][dwn[i][j]];
                }
                M+=tot*tot;
            }    
        printf("Case #%d: %lld\n",++cas,S*S-M);
    }
    return 0;
}

 

posted @ 2016-10-09 19:22  TenderRun  阅读(325)  评论(0编辑  收藏  举报