组合计数·几何统计

先来看相关题目:

1. Uva 10884 Persephone

题意:用$n(n \leq 100)$根长度为$1$的木条拼出一个周长为$n$的,各边与坐标轴平行的多边形,并要求其最小外接矩形周长也是$n$,如下图所示。求满足条件的方案数。

分析:容易看出满足条件的一定是凸多边形,并且如果只考虑其在垂直方式向单侧轮廓的变化,具有单峰性。并且该多边形需要在四个方向上与外界多边形有一段且仅有一段公共边,因此我们可以利用这些特征对图形分类,即dp。用$dp(u, l, r, o)$表示当前行(两侧轮廓在该行位置已确定)为$u$,且左右位置分别为$l, r$,$o$是两位的二进制数,高位为$0$表示左侧边仍在$\leftarrow$状态,即峰值之前,为$1$表示经过峰值且严格小于峰值,低位对应右侧边的情况。于是根据$o$的取值和$l, r$的位置可以计算出下一步可达的所有合法状态,最终当我们到达最后一行时,如某一侧经过峰值或者在最左(最优)并且另一侧也满足该条件说明构造的轮廓是合法的,否则不合法。

这样做对于给定高度$r$和宽度$c$的外界矩形共有$O(r^2c)$个状态,状态转移复杂度为$O(c^2)$,对应时间复杂度为$O(r^2c^3)$,而一共需要计算的矩形有$O(n^2)$个,这样会超时,需要一点优化,固定宽度,计算最宽的矩形,那么同宽度的其余矩形的方案可由其$dp$数组得出。尽管如此,下面的java代码还是跑了800多ms。

代码:

  1 import java.io.*;
  2 import java.math.BigInteger;
  3 import java.util.Arrays;
  4 import java.util.Iterator;
  5 import java.util.Scanner;
  6 import java.util.TreeSet;
  7
  8 public class Main {
  9     private final static int maxn = 55;
 10     BigInteger[][] ans = new BigInteger[maxn][maxn];
 11     BigInteger[][][][] dp = new BigInteger[maxn][maxn][maxn][4];
 12     private int row, col;
 13     private final static BigInteger neg = BigInteger.valueOf(-1);
 14     BigInteger dfs(int u, int l, int r, int o){
 15         if(dp[u][l][r][o].compareTo(neg) != 0) return dp[u][l][r][o];
 16         if(u == row){
 17             boolean lhs = ((o >> 1) & 1) == 1 || l == 1;
 18             boolean rhs = (o & 1) == 1 || r == col;
 19             BigInteger tans = lhs && rhs ? BigInteger.ONE : BigInteger.ZERO;
 20             return dp[u][l][r][o] = tans;
 21         }
 22         BigInteger tem = BigInteger.ZERO;
 23         if(o == 0){
 24             for(int tl = l; tl >= 1; tl--) for(int tr = r; tr <= col; tr++){
 25                 tem = tem.add(dfs(u + 1, tl, tr, 0));
 26             }
 27             if(l == 1) for(int tl = l + 1; tl < r; tl++) for(int tr = r; tr <= col; tr++){
 28                 tem = tem.add(dfs(u + 1, tl, tr, 2));
 29             }
 30             if(r == col) for(int tr = r - 1; tr > l; tr--) for(int tl = l; tl >= 1; tl--){
 31                 tem = tem.add(dfs(u + 1, tl, tr, 1));
 32             }
 33             if(l == 1 && r == col) for(int tl = l + 1; tl < r; tl++) for(int tr = r - 1; tr > tl; tr--){
 34                 tem = tem.add(dfs(u + 1, tl, tr, 3));
 35             }
 36         }else if(o == 1){
 37             for(int tr = r; tr > l; tr--) for(int tl = l; tl >= 1; tl--){
 38                 tem = tem.add(dfs(u + 1, tl, tr, 1));
 39             }
 40             if(l == 1) for(int tl = l + 1; tl < r; tl++) for(int tr = r; tr > tl; tr--){
 41                 tem = tem.add(dfs(u + 1, tl, tr, 3));
 42             }
 43         }else if(o == 2){
 44             for(int tl = l; tl < r; tl++) for(int tr = r; tr <= col; tr++){
 45                 tem = tem.add(dfs(u + 1, tl, tr, 2));
 46             }
 47             if(r == col) for(int tr = r - 1; tr > l; tr--) for(int tl = l; tl < tr; tl++){
 48                 tem = tem.add(dfs(u + 1, tl, tr, 3));
 49             }
 50         }else if(o == 3){
 51             for(int tl = l; tl < r; tl++) for(int tr = r; tr > tl; tr--){
 52                 tem = tem.add(dfs(u + 1, tl, tr, 3));
 53             }
 54         }
 55         return dp[u][l][r][o] = tem;
 56     }
 57
 58     void init(){
 59         int lim = 53;
 60         for(int j = 2; j <= lim; j++){
 61             col = j;
 62             row = lim - j;
 63             if(col > row) continue;
 64             for(int u = 0; u < maxn; u++) for(int v = 0; v < maxn; v++) for(int w = 0; w < maxn; w++){
 65                 for(int id = 0; id < 4; id++) dp[u][v][w][id] = neg;
 66             }
 67             for(int l = 1; l <= col; l++) for(int r = l + 1; r <= col; r++) dfs(2, l, r, 0);
 68             for(int i = j; i + j <= lim; i++){
 69                 BigInteger tans = BigInteger.ZERO;
 70                 int pos = row - i + 2;
 71                 for(int l = 1; l <= col; l++) for(int r = l + 1; r <= col; r++){
 72                     tans = tans.add(dp[pos][l][r][0]);
 73                 }
 74                 ans[i][j] = ans[j][i] = tans;
 75             }
 76         }
 77         //System.out.println("ok");
 78     }
 79     BigInteger getAns(int num){
 80         if((num & 1) == 1) return BigInteger.ZERO;
 81         num /= 2;
 82         BigInteger tans = BigInteger.ZERO;
 83         for(int i = 1; i < num; i++) tans = tans.add(ans[i + 1][num - i + 1]);
 84         return tans;
 85     }
 86
 87     public void solve(){
 88         init();
 89         //System.out.println("ok");
 90         int T, kase = 0;
 91         Scanner cin = new Scanner(System.in);
 92         while(cin.hasNextInt()){
 93             T = cin.nextInt();
 94             while(T-- > 0){
 95                 int num = cin.nextInt();
 96                 BigInteger tans = getAns(num);
 97                 System.out.println("Case #" + (++kase) + ": " + tans);
 98             }
 99         }
100     }
101     public static void main(String []argc){
102         Main e = new Main();
103         e.solve();
104     }
105 }

code:

时间: 2024-10-09 21:12:08

组合计数·几何统计的相关文章

组合计数&#183;棋盘统计

相关习题: 1. Uva 10237 Bishops 题意:两个象不攻击,当且仅当它们不处在同一条斜线上.输入整数$n(n \leq 30)$,统计在一个$n \times n$的棋盘上放$k$个互不攻击的象有多少种方法.如$N=8, k = 6$时有$5599888$种.

bzoj 1004 Cards 组合计数

这道题考察的是组合计数(用Burnside,当然也可以认为是Polya的变形,毕竟Polya是Burnside推导出来的). 这一类问题的本质是计算置换群(A,P)中不动点个数!(所谓不动点,是一个二元组(a,p),a∈A,p∈P ,使得p(a)=a,即a在置换p的作用后还是a). Polya定理其实就是告诉了我们一类问题的不动点数的计算方法. 对于Burnside定理的考察,我见过的有以下几种形式(但归根结底还是计算不动点数): 1.限制a(a∈A)的特点,本题即是如此(限制了各颜色个数,可以

HDU4675-GCD of Sequence(数论+组合计数)

GCD of Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 949    Accepted Submission(s): 284 Problem Description Alice is playing a game with Bob. Alice shows N integers a1, a2, -, aN, an

HDU 4832 组合计数dp

Chess Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 509    Accepted Submission(s): 198 Problem Description 小度和小良最近又迷上了下棋.棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M).在他们的规则中,"王"在棋盘上的走法遵循十字

ArcGIS教程:分区几何统计的工作原理

分区几何统计工具可返回栅格中各个区域的几何或形状的相关信息.区域 (zone) 不必是单个连续实体,它可以由多个不相连的区域(area 或 region)组成. 通过分区几何统计工具可以计算四种类型的几何,具体根据以下几何类型参数确定: 面积 各个区域的面积. 周长 各个区域的周长. 厚度 区域中最深的点距其周围像元的距离. 质心 定位各个区域的质心. 以表格显示分区几何统计工具可计算所有几何测量值,但是会以表格形式返回结果,而不是输出栅格形式. 面积.周长和厚度几何类型的输出结果都以地图单位表

【51nod】1222 最小公倍数计数 莫比乌斯反演+组合计数

[题意]给定a和b,求满足a<=lcm(x,y)<=b && x<y的数对(x,y)个数.a,b<=10^11. [算法]莫比乌斯反演+组合计数 [题解]★具体推导过程参考:51nod1222 最小公倍数计数 过程运用到的技巧: 1.将所有i和j的已知因子提取出来压缩上届. 2.将带有μ(k)的k提到最前面,从而后面变成单纯的三元组形式. 最终形式: $$ans=\sum_{k=1}^{\sqrt n} \mu(k)  \sum_{d}    \sum_{i} \s

[Gym-101981J] Prime Game (组合计数)

题意:求for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) sum += f[i][j]; f[i][j]表示在序列从 i 位乘到第 j 位所形成的新的数的 不同质因子的个数. 思路:说是话,拿到题还是一开始想着能不能进行递推,比如先将每一个数进行 质因分解 然后用set不断更新统计个数来求和.但这样无论怎样都无法优化 (n^2) ,所以换思路再想. 就忽然想到了以前有一道做过的原题,题意是:给定一个长度为n的序列,然后求出每一个子区间不同数的个数和.而这一

BZOJ 1833 数字计数(统计[a,b]每个数字出现次数)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1833 题意:给定区间[a,b].求区间内0到9每个数字出现的次数. 思路:f[i][j]表示到后i位是否全 0(j=1表示i位之前全0)这个状态某个数字出现的次数,p[i][j]表示这个状态后面有多少个数字.那么当前枚举到的数字为要统计的数字时,答案加 上后面还有多少种数字,即下一个状态的p值.那么我们枚举要统计的数字依次统计即可. i64 f[20][2],p[20][2]; i64

Yue Fei&#39;s Battle(组合计数递推)

//求一个直径为 k 的树有多少种形态,每个点的度不超过 3 // 非常完美的分析,学到了,就是要细细推,并且写的时候要细心 还有除法取模需要用逆元 #include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> using namespace std; #define MOD 1000000007 #define L