zoukankan      html  css  js  c++  java
  • 题解 LA3720

    题目大意 多组数据,每组数据给定两个整数 (n,m),请求出 (n imes m) 的点阵(即 ((n-1) imes(m-1)) 的方格)中有多少条非水平竖直的经过至少两个格点的不同直线。

    分析 这道题有多种解法,这里给出最经典的,使用容斥原理的解法。

    (dp[i][j]) 表示 (i imes j) 的方格中,经过 ((0,0)) 顶点的所有至少经过两个点的不同直线数(比如 (dp[3][2]=5))。

    dp[3][2]=5

    不难发现,(dp) 数组满足可加可减性,也即可以用容斥原理来递推。且点 ((i,j)) 当且仅当 (GCD(i,j)=1) 时可以为 (dp[i][j]) 贡献 (1)。所以有

    [dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+[gcd(i,j)=1] ]

    现在考虑如何用 (dp) 数组来递推出最终答案。我们记 (i imes j) 方格中从左下到右上的不同直线数为 (ans[i][j]),则最终答案为 (2 imes ans[i][j])(比如 (ans[3][2]=14))。

    ans[3][2]=14

    不难看出,(ans) 数组也满足可加可减性,可以用容斥原理来递推。且点 ((i,j)) 构成的新直线当且仅当它在 (dp[i][j]) 中而不在 (dp[i/2][j/2]) 中才有贡献,这是因为如果它在被重复计算过则一定在 (dp[i/2][j/2]) 中被计算过(为什么),所以有

    [ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1]+dp[i][j]-dp[i/2][j/2] ]

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 305;
    const int maxm = 305;
    
    int n, m;
    int dp[maxn][maxm];
    int ans[maxn][maxm];
    
    void Init(int N, int M)
    {
    	for(int i = 1; i <= N; ++i)
    		for(int j = 1; j <= M; ++j)
    			dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + (__gcd(i, j) == 1);
    	
    	for(int i = 1; i <= N; ++i)
    		for(int j = 1; j <= M; ++j)
    			ans[i][j] = ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1] + dp[i][j] - dp[i / 2][j / 2];
    }
    
    int main()
    {
    	Init(300, 300);
    	while(~scanf("%d%d", &n, &m) && n && m)
    		printf("%d
    ", 2 * ans[n - 1][m - 1]);
    }
    
  • 相关阅读:
    jbpm入门样例
    MinGW 介绍
    Linux守护进程的编程实现
    完毕port(CompletionPort)具体解释
    Linux makefile 教程 很具体,且易懂
    mysql数据文件迁移到新的硬盘分区的方法
    winform正在使用dsoframer迅速&quot;Unable to display the inactive document.Click here to reacitive the document.&quot;
    Android学习路径(七)建立Action Bar
    FreeBSD包管理
    BZOJ 1096 ZJOI2007 仓库建设 边坡优化
  • 原文地址:https://www.cnblogs.com/whx1003/p/12198915.html
Copyright © 2011-2022 走看看