UVa 1393 Highways (动态规划)

题目

题目大意

有一个\(n\)行\(m\)列(\(1 ≤ n, m ≤ 300\))的点阵, 问: 一共有多少条非水平非竖直的直线至少穿过其中两个点? 例如, \(n = 2\), \(m = 4\)时答案为\(12\), \(n = m = 3\)时答案为\(14\)。

题解

一开始看到题目我立马想到了\(SPOJ 104 Highways\)(基尔霍夫矩阵-树定理), 然而本题跟这个定理完全没有关系。

首先考虑如何判断是否形成一条之前没有出现过的直线, 如果它向量两坐标的最大公约数为\(1\)则没有出现过。我们考虑用\(dp_{i\ j}\)表示表示向量\((x, y)\)(\(x ≤ i\), \(y ≤ j\))共有多少个\((x, y) = 1\)的, 递推式为:

\[dp_{i\ j} = dp_{i - 1\ j} + dp_{i\ j - 1} - dp_{i - 1\ j - 1} ((i, j) ≠ 1)\]

\[dp_{i\ j} = dp_{i - 1\ j} + dp_{i\ j - 1} - dp_{i - 1\ j - 1} + 1 ((i, j) = 1)\]

接下来处理所有点, 到\((i, j)\)时, 内部各点与他组成的向量范围都在\(\{(x, y)|x∈[1, i), y∈[1, j), x, y∈N^*\}\)内, 那么可以用\(dp_{i - 1\ j - 1}\)表示其中有多少与其互质, 再减去重复计算的(\(dp_{\frac{i - 1}{2}\ \frac{j - 1}{2}}\))。为了方便我们将所有\(i\), \(j\)增加\(1\), 最后减\(1\)即可。

代码

#include <cstdio>
long long ans[310][310], dp[310][310];
int n, m;
inline long long GreatestCommonDivisor(const long long&, const long long&);
int main(int argc, char const *argv[]) {
  for (register long long i(1); i <= 300ll; ++i) {
    for (register long long j(1); j <= 300ll; ++j) {
      dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + (GreatestCommonDivisor(i, j) == 1);
      ans[i][j] = ans[i - 1][j] + ans[i][j - 1] - ans[i - 1][j - 1] + dp[i][j] - dp[i >> 1][j >> 1];
    }
  }
  while (~scanf("%d %d", &n, &m) && (n || m)) {
    printf("%lld\n", ans[n - 1][m - 1] << 1);
  }
  return 0;
}
inline long long GreatestCommonDivisor(const long long &a, const long long &b) {
  return b ? GreatestCommonDivisor(b, a % b) : a;
}

原文地址:https://www.cnblogs.com/forth/p/9726252.html

时间: 2024-10-09 09:09:25

UVa 1393 Highways (动态规划)的相关文章

UVA - 1393 Highways

Description Hackerland is a happy democratic country with m×n cities, arranged in a rectangular m by n grid and connected by m roads in the east-west direction and n roads in the north-south direction. By public demand, this orthogonal road system is

uva 1393 - Highways(容斥原理)

题目连接:uva 1393 - Highways 题目大意:给定一个m?n的矩阵,将矩阵上的点两两相连,问有多少条直线至少经过两点. 解题思路:头一次做这样的题目,卡了一晚上. dp[i][j]即为i?j的矩阵中有多少条红色的线,然后最后答案*2,即水平翻转下蓝色的线.非常easy发现,全部的线都过ij互质的点(即最大公约数为1).然后用容斥原理求出ans. #include <cstdio> #include <cstring> const int N = 305; int n,

UVA 1393 - Highways (容斥原理计数)

题目链接:1393 - Highways 题意:给定一个n * m的点阵,问两两相连后,能组成多少条至少穿过两个点的直线,并且不是水平或垂直的 思路:找过两点的线段,由于是整数坐标,只要他的斜率不是整数,即x / y不是整数就能满足答案,然后先记录下这所有的位置,然后利用容斥原理求出对应每个点可以连出多少条这样的线段,最后去求和,求和的时候要注意,由于有一些是重复计算了,比如1 1 和 2 2 连,2 2 和 3 3 连,这样其实是算一条的,所以最后在求和的时候要扣掉重复的部分,直接减去sum[

UVA 1393 Highways(数学思想)

题意:给你n.m(n,m<=200),问你有多少条非水平.非垂直的直线有多少条经过至少两个点 题解:我们需要枚举的是只画一条线的矩形,对于大小a*b的矩形必须保证gcd(a,b)=1才能不重复 接着对于每个矩形可以放的位置有(n-a)(m-b)个,但是如果有矩形在某个矩形的左上方就会再次重复 因此只需要再减去max(0,n-2*a)*max(0,m-2*b)就好 import java.util.Scanner; public class Main{ static int Max=305; st

UVA 1393 Highways,UVA 12075 Counting Triangles —— (组合数,dp)

先看第一题,有n*m个点,求在这些点中,有多少条直线,经过了至少两点,且不是水平的也不是竖直的. 分析:由于对称性,我们只要求一个方向的线即可.该题分成两个过程,第一个过程是求出n*m的矩形中,dp[i][j]代表在这个矩形中终点是到(i,j)这个点的满足题意的直线条数,那么,用dp的话就可以得出递推关系:由长和宽分别小1的左右两个矩形中满足题意的线的条数减去他们共有的矩形中满足的线的条数(容斥减去重复部分),之后还要判断从最左上角的点(1,1)到(i,j)是否可以组成一条线,这个条件是gcd(

UVa 1393 (容斥原理、GCD) Highways

题意: 给出一个n行m列的点阵,求共有多少条非水平非竖直线至少经过其中两点. 分析: 首先说紫书上的思路,编程较简单且容易理解.由于对称性,所以只统计“\”这种线型的,最后乘2即是答案. 枚举斜线包围盒的大小,如果盒子的长宽ab互质,则是可以的.这种盒子共有(m-a)(n-b)个,但要减去其中重复的.如果有一个长宽为2a和2b的大盒子,则计数右下角的小盒子的同时,左上角的小盒子会重复,所以要减去重复的盒子的个数c = max(0, m-2a) * max(0, n-2b) 最后gcd(a, b)

1393 - Highways 计数问题

Hackerland is a happy democratic country with m×n cities, arranged in a rectangular m by ngrid and connected by m roads in the east-west direction and n roads in the north-south direction. By public demand, this orthogonal road system is to be supple

uva 116(动态规划起步第三天 DAG)

一道比较简单的动态规划的题,求从第一列的任何位置 到达最后一列 和的最小值. 所以这个状态可以是 列,在每一列有三种决策,直行,右上,右下.DP[i][j] 表示在第i行,j列到达最后一列的最小支出. 那么有了状态,我们可以进行转移,DP[i][j] = min{DP[i + 1][j + 1],DP[i][j + 1],DP[i - 1][j + 1]} + a[i][j];(跟数字三角形差不多) 1 #include <iostream> 2 #include <cstdio>

UVa 10147 - Highways

题目:在一个平面上有很多点,其中一些点已经被直线段连接,现在要把所有点连成一个整体, 要求新加入的直线段长度和最小. 分析:最小生成树.这里使用kruskal算法,先把一直线段的集合合并(并查集),然后在计算即可. 说明:╮(╯▽╰)╭. #include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include