zoukankan      html  css  js  c++  java
  • bzoj 4767 两双手

    题目传送门

      传送门I

      传送门II

    题目大意

      一个无限大的棋盘上有一只马,设马在某个时刻的位置为$(x, y)$, 每次移动可以将马移动到$(x + A_x, y + A_y)$或者$(x + B_x, y + B_y)$。棋盘上有$n$个禁止位置不能经过,问马从$(0, 0)$走到$(E_x, E_y)$的方案数。

      容斥是显然的。

      每确定经过$k$个禁止位置的方案数的容斥系数是$(-1)^{k}$。

      考虑带上容斥系数来动态规划,

      注意到去掉重复的禁止位置后,$(0, 0), (E_x, E_y)$以及禁止位置构成了一个DAG。

      容斥相当于求从$(0, 0)$到$(E_x, E_y)$的经过偶数个禁止位置的路径数减去经过奇数个禁止位置的路径数。

      直接动态规划计数就好了。

    Code

      1 /**
      2  * bzoj
      3  * Problem#4767
      4  * Accepted
      5  * Time: 333ms
      6  * Memory: 10716k
      7  */
      8 #include <iostream>
      9 #include <cassert>
     10 #include <cstdlib>
     11 #include <cstdio>
     12 #include <queue>
     13 #include <set>
     14 using namespace std;
     15 typedef bool boolean;
     16 
     17 const int N = 505, M = 1e9 + 7, D = 1e6 + 1;
     18 
     19 int add(int a, int b) {
     20     return ((a += b) >= M) ? (a - M) : (a);
     21 }
     22 
     23 int sub(int a, int b) {
     24     return ((a -= b) < 0) ? (a + M) : (a);
     25 }
     26 
     27 int mul(int a, int b) {
     28     return a * 1ll * b % M;
     29 }
     30 
     31 #define pii pair<int, int>
     32 #define fi first
     33 #define sc second
     34 
     35 void exgcd(int a, int b, int& x, int& y) {
     36     if (!b)
     37         x = 1, y = 0;
     38     else {
     39         exgcd(b, a % b, y, x);
     40         y -= (a / b) * x;
     41     }
     42 }
     43 
     44 int inv(int a, int n) {
     45     int x, y;
     46     exgcd(a, n, x, y);
     47     return (x < 0) ? (x + n) : (x);
     48 }
     49 
     50 int fac[D], _fac[D];
     51 
     52 inline void prepare() {
     53     fac[0] = 1;
     54     for (int i = 1; i < D; i++)
     55         fac[i] = mul(fac[i - 1], i);
     56     _fac[D - 1] = inv(fac[D - 1], M);
     57     for (int i = D; --i; )
     58         _fac[i - 1] = mul(_fac[i], i);
     59 }
     60 
     61 int comb(int n, int m) {
     62     if (n < m)
     63         return 0;
     64     return mul(fac[n], mul(_fac[n - m], _fac[m]));
     65 }
     66 
     67 boolean Solve(int a1, int b1, int a2, int b2, int c1, int c2, pii& sol) {
     68     int d = c2 * a1 - a2 * c1, f = a1 * b2 - a2 * b1;
     69     if (d % f)
     70         return false;
     71     sol.sc = d / f;
     72     if (a1) {
     73         d = c1 - b1 * sol.sc;
     74         if (d % a1)
     75             return false;
     76         sol.fi = d / a1;
     77     } else {
     78         d = c2 - b2 * sol.sc;
     79         if (d % a2)
     80             return false;
     81         sol.fi = d / a2;
     82     }
     83     return sol.fi >= 0 && sol.sc >= 0; 
     84 }
     85 
     86 int n, Ex, Ey;
     87 int Ax, Ay, Bx, By;
     88 pii ps[N];
     89 int deg[N];
     90 set<pii> s;
     91 boolean g[N][N];
     92 
     93 //#define _DEBUG_
     94 #ifdef _DEBUG_
     95 FILE* fin = fopen("6.in", "r");
     96 #else
     97 FILE* fin = stdin;
     98 #endif
     99 
    100 boolean Solve(pii ps, pii pt, pii& sol) {
    101     return Solve(Ax, Bx, Ay, By, pt.fi - ps.fi, pt.sc - ps.sc, sol);
    102 }
    103 
    104 inline void init() {
    105     fscanf(fin, "%d%d%d", &Ex, &Ey, &n);
    106     fscanf(fin, "%d%d%d%d", &Ax, &Ay, &Bx, &By);
    107     for (int i = 1; i <= n; i++) {
    108         fscanf(fin, "%d%d", &ps[i].fi, &ps[i].sc);
    109         if (s.count(ps[i]))
    110             i--, n--;
    111         s.insert(ps[i]);
    112     }
    113 }
    114 
    115 int f[N];
    116 queue<int> que;
    117 inline void solve() {
    118     int t = n + 1;
    119     pii p, S(0, 0), T(Ex, Ey);
    120     ps[0] = S, ps[t] = T;
    121     for (int i = 1; i <= n; i++)
    122         if (Solve(S, ps[i], p))
    123             g[0][i] = true, deg[i]++;
    124     for (int i = 1; i <= n; i++)
    125         for (int j = 1; j <= n; j++)
    126             if ((i ^ j) && Solve(ps[i], ps[j], p))
    127                 g[i][j] = true, deg[j]++, assert(!g[j][i]);
    128     for (int i = 1; i <= n; i++)
    129         if (Solve(ps[i], T, p))
    130             g[i][t] = true, deg[t]++;
    131     if (Solve(S, T, p))
    132         g[0][t] = true, deg[t]++;
    133 
    134     f[0] = 1;
    135     que.push(0);
    136     while (!que.empty()) {
    137         int e = que.front();
    138         que.pop();
    139         for (int i = 1; i <= t; i++) {
    140             if (!g[e][i])
    141                 continue;
    142             Solve(ps[e], ps[i], p);
    143             if (i && i != t)
    144                 f[i] = sub(f[i], mul(f[e], comb(p.fi + p.sc, p.fi)));
    145             else
    146                 f[i] = add(f[i], mul(f[e], comb(p.fi + p.sc, p.fi)));
    147             if (!(--deg[i]))
    148                 que.push(i);
    149         }
    150     }
    151 //    for (int i = 1; i <= n; i++)
    152 //        assert(!deg[i]);
    153 //        if (deg[i])
    154 //            cerr << i << " " << ps[i].fi << " " << ps[i].sc << endl;
    155     printf("%d
    ", f[t]);
    156 }
    157 
    158 int main() {
    159     prepare();
    160     init();
    161     solve();
    162     return 0;
    163 }
  • 相关阅读:
    重温数据结构与算法(1) 构建自己的时间测试类
    读<<CLR via C#>>总结(11) 详谈事件
    读<<CLR via C#>>总结(13) 详谈泛型
    重温数据结构与算法(2) 编程中最常用,最通用的数据结构数组和ArrayList
    由String类的Split方法所遇到的两个问题
    读<<CLR via C#>>总结(6) 详谈实例构造器和类型构造器
    让我们都建立自己的知识树吧
    读<<CLR via C#>>总结(5) 如何合理使用类型的可见性和成员的可访问性来定义类
    读<<CLR via C#>>总结(10) 详谈委托
    读<<CLR via C#>>总结(4) 值类型的装箱和拆箱
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9901239.html
Copyright © 2011-2022 走看看