hdu5794 A Simple Chess 容斥+Lucas 从(1,1)开始出发,每一步从(x1,y1)到达(x2,y2)满足(x2?x1)^2+(y2?y1)^2=5, x2>x1,y2>y1; 其实就是走日字。而且是往(n,m)方向走的日字。还有r个障碍物,障碍物不可以到达。求(1,1)到(n,m)的路径条数。

A Simple Chess

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2597    Accepted Submission(s): 691

Problem Description

There is a n×m board, a chess want to go to the position
(n,m) from the position (1,1).
The chess is able to go to position (x2,y2) from the position (x1,y1), only and if only x1,y1,x2,y2 is satisfied that (x2?x1)2+(y2?y1)2=5, x2>x1, y2>y1.
Unfortunately, there are some obstacles on the board. And the chess never can stay on the grid where has a obstacle.
I want you to tell me, There are how may ways the chess can achieve its goal.

Input

The input consists of multiple test cases.
For each test case:
The first line is three integers, n,m,r,(1≤n,m≤1018,0≤r≤100), denoting the height of the board, the weight of the board, and the number of the obstacles on the board.
Then follow r lines, each lines have two integers, x,y(1≤x≤n,1≤y≤m), denoting the position of the obstacles. please note there aren‘t never a obstacles at position (1,1).

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 answer after module 110119.

Sample Input

1 1 0
3 3 0
4 4 1
2 1
4 4 1
3 2
7 10 2
1 2
7 1

Sample Output

Case #1: 1
Case #2: 0
Case #3: 2
Case #4: 1
Case #5: 5

Author

UESTC

Source

2016 Multi-University Training Contest 6

/**
题目:A Simple Chess
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794
题意:从(1,1)开始出发,每一步从(x1,y1)到达(x2,y2)满足(x2?x1)^2+(y2?y1)^2=5, x2>x1,y2>y1;
其实就是走日字。而且是往(n,m)方向走的日字。还有r个障碍物,障碍物不可以到达。求(1,1)到(n,m)的路径条数。
思路:容斥+Lucas

如果没有障碍物:那么每一次可以选择从(x1,y1)到达(x1+2,y1+1)或者(x1+1,y1+2);
那么设选择了x次(x1+2,y1+1),y次(x1+1,y1+2)
那么: x1+2*x+y = n;  => 2*x+y = n-x1;
       x+2*y+y1 = m;     2*y+x = m-y1;

x = (2*n-2*x1-m+y1)/3;
y = (2*m-2*y1-n+x1)/3;  说明如果2*n-2*x1-m+y1或者2*m-2*y1-n+x1不是3的倍数,(x,y都必须非负整数),那么无法到达。

否则路径条数为:C(x+y,x);

存在障碍物:
假设只有一个障碍物,那么用总的路径条数sum-经过这一个障碍物的路径条数dp[1]。
假设存在两个障碍物,那么sum-经过的第一个障碍物为编号1的路径条数-经过的第一个障碍物为编号2的路径条数。(注意:第一个!!!)

经过的第一个障碍物为编号1的路径条数:从(1,1)到达(x1,y1)的路径条数乘以(x1,y1)到达(n,m)的路径条数。
经过的第一个障碍物为编号2的路径条数:(从(1,1)到达(x2,y2)的路径条数-从(1,1)到达(x1,y1)然后从(x1,y1)到达(x2,y2)的路径条数)
乘以 从(x2,y2)到达(n,m)的路径条数。

当多个障碍物时,方法同上处理。

处理c(x+y,x)%mod用Lucas定理。
*/

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> P;
const int maxn = 1e6+10;
const int mod = 110119;
LL f[mod+10];///阶乘。
LL inv[mod+10];///逆元
LL exgcd(LL a, LL b, LL &x, LL &y)///扩展欧几里得;
{
    if (!b)
    {
        x = 1;
        y = 0;
        return a;
    }
    LL gcd = exgcd(b, a % b, x, y);
    LL t = x;
    x = y;
    y = t - (a / b) * x;
    return gcd;
}
LL inverse(LL num, LL mod)///求逆元;
{
    LL x, y;
    exgcd(num, mod, x, y);
    return (x % mod + mod) % mod;
}
void init()///如果mod小,那么可以线性筛逆元。
{
    inv[1] = 1;
    for(int i = 2; i < mod; i++){
        inv[i] = (mod-mod/i)*inv[mod%i]%mod;
    }
    f[0] = 1;
    for(int i = 1; i < mod; i++){///预处理阶乘。
        f[i] = f[i-1]*i%mod;
    }
}
LL mult(LL a,LL b,LL p)///解决 大数a*b%p溢出long long 的方法;
{
    LL ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%p;
        b>>=1;
        a=(a+a)%p;
    }
    return ans;
}
LL C(LL a, LL b, LL mod)///实现C(n,m)%p
{

    if (b > a)
        return 0;
    return mult(mult(f[a],inv[f[b]],mod),inv[f[a-b]],mod);/// a!/(b!*(a-b)!);
}
LL lucas(LL n, LL m, LL p)///卢卡斯定理实现;c(n,m)%p;
{
    if (m == 0)
        return 1;
    return mult(C(n % p, m % p, p),lucas(n / p, m / p, p),p);
}
LL solve(LL x1,LL y1,LL n,LL m)
{
    if((2*n-2*x1-m+y1)%3!=0) return 0;
    if((2*m-2*y1-n+x1)%3!=0) return 0;
    LL x = (2*n-2*x1-m+y1)/3;
    LL y = (2*m-2*y1-n+x1)/3;
    if(x<0||y<0) return 0;
    return lucas(x+y,y,mod)%mod;
}
LL n, m, r;
struct node
{
    LL x, y;
    bool operator < (const node&k)const{
        if(x==k.x) return y<k.y;
        return x<k.x;
    }
}t[104];
LL ans[104];
int main()
{
    int cas = 1;
    init();///初始化逆元。
    while(scanf("%lld%lld%lld",&n,&m,&r)!=EOF)
    {
        for(int i = 0; i < r; i++){
            scanf("%lld%lld",&t[i].x,&t[i].y);
        }
        sort(t,t+r);

        LL sum = solve(1,1,n,m);
        for(int i = 0; i < r; i++){
            ans[i] = solve(1,1,t[i].x,t[i].y);
            for(int j = 0; j < i; j++){
                ans[i] = (ans[i]-ans[j]*solve(t[j].x,t[j].y,t[i].x,t[i].y)%mod+mod)%mod;
            }
        }
        //cout<<"sum = "<<sum<<endl;
        //cout<<"ans[0] = "<<ans[0]<<endl;
        for(int i = 0; i < r; i++){
            sum = (sum-ans[i]*solve(t[i].x,t[i].y,n,m)%mod+mod)%mod;
        }
        printf("Case #%d: %lld\n",cas++,sum);
    }
    return 0;
}
时间: 2024-10-01 20:23:55

hdu5794 A Simple Chess 容斥+Lucas 从(1,1)开始出发,每一步从(x1,y1)到达(x2,y2)满足(x2?x1)^2+(y2?y1)^2=5, x2>x1,y2>y1; 其实就是走日字。而且是往(n,m)方向走的日字。还有r个障碍物,障碍物不可以到达。求(1,1)到(n,m)的路径条数。的相关文章

hdu-5794 A Simple Chess(容斥+lucas+dp)

题目链接: A Simple Chess Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Problem Description There is a n×m board, a chess want to go to the position (n,m) from the position (1,1).The chess is able to go to position (

HDU5794 A Simple Chess 容斥+lucas

分析:转自http://blog.csdn.net/mengzhengnan/article/details/47031777 一点感想:其实这个题应该是可以想到的,但是赛场上并不会 dp[i]的定义很巧妙,容斥的思路也非常清晰 然后就是讨论lucas的用法,首先成立的条件是mod是素数 但是如果这个题mod很大,组合数取模感觉就不太可做了 我认为当mod很大时,n应该很小可以预处理,但是n很大时mod应该比较小,这样也可以预处理 如果n和mod都很大我就不会了.... 这个题在预处理的时候,同

A Simple Chess---hdu5794(容斥+Lucas)

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5794 题意:给你一个n*m的网格,问从(1, 1)走到(n, m)的方案数是多少,其中有r个点是不可到达的: 根据公式我们可以知道每次只能走”日"型: 路径如上图所示,我们可以看到有很多点是不可达的,可达点都是满足(x+y)%3=2的;路径可以看成一个斜着放置的杨辉三角.我们只需要把坐标转换一下即可,这是没有障碍时的方案数: 让(1,1)到(n,m)中如果有一个障碍,那么我们可以用起点到

hdu1695(莫比乌斯)或欧拉函数+容斥

题意:求1-b和1-d之内各选一个数组成数对,问最大公约数为k的数对有多少个,数对是有序的.(b,d,k<=100000) 解法1: 这个可以简化成1-b/k 和1-d/k 的互质有序数对的个数.假设b=b/k,d=d/k,b<=d.欧拉函数可以算出1-b与1-b之内的互质对数,然后在b+1到d的数i,求每个i在1-b之间有多少互质的数.解法是容斥,getans函数参数的意义:1-tool中含有rem位置之后的i的质因子的数的个数. 在 for(int j=rem;j<=factor[i

一些经典的容斥问题

在平面中给$n$个点,求这$n$个点构成的三角形/锐角三角形的个数. 求三角形的个数比较简单.首先全集是$\binom{n}{3}$,然后考虑补集,补集就是三点共线的点对.所以我们可以枚举每一个点,然后为了避免算重,我们接下来只考虑标号比当前点小的点.接着就进行极角排序,这样就可以统计出当前点所在的所有直线以及直线上的点的个数.设某直线上有$m$个点,那么答案就减去$\binom{m}{3}$即可.注意处理重点的情况. 求锐角三角形的个数也比较简单,只不过补集除了三点共线之外,还会有钝角三角形和

hdu_5794_A Simple Chess(lucas+dp)

题目链接:hdu_5794_A Simple Chess 题意: 给你n,m,从(1,1)到(n,m),每次只能从左上到右下走日字路线,有k(<=100)的不能走的位置,问你有多少方案 题解: 画图可看到路线是一个杨辉三角的图,然后我们可以将对应的x,y转换到对应的点上,也可以吧杨辉三角看成一个平行四边形, 我这里看成的平行四边形,设dp[i]为从起点到第i个障碍物的的方案数,那么dp[i]=dp[i]-sum(dp[j](第j个点能走到i这个点)*(j到i的方案数)). 然后我们把终点放到最后

HDU 5794 A Simple Chess(杨辉三角+容斥原理+Lucas)

题目链接 A Simple Chess 打表发现这其实是一个杨辉三角…… 然后发现很多格子上方案数都是0 对于那写可能可以到达的点(先不考虑障碍点),我们先叫做有效的点 对于那些障碍,如果不在有效点上,则自动忽略 障碍$(A, B)$如果有效,那么就要进行如下操作: 以这个点为一个新的杨辉三角的顶点,算出目标点的坐标$(x, y)$. 目标点的答案减去$C(A, B) * C(x, y)$的值. 但是这样会造成重复计算,原因是障碍之间可能有相互影响的关系. 这个时候就要考虑容斥原理,DFS消除这

HDU 5794 A Simple Chess(卢卡斯定理 + 容斥原理)

传送门 A Simple Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 667    Accepted Submission(s): 168 Problem Description There is a n×m board, a chess want to go to the position (n,m) from the

hdu 1695 GCD 欧拉函数+容斥

题意:给定a,b,c,d,k x属于[1 , c],y属于[1 , d],求满足gcd(x,y)=k的对数.其中<x,y>和<y,x>算相同. 思路:不妨设c<d,x<=y.问题可以转化为x属于[1,c / k ],y属于[1,d/k ],x和y互质的对数. 那么假如y<=c/k,那么对数就是y从1到c/k欧拉函数的和.如果y>c/k,就只能从[ c/k+1 , d ]枚举,然后利用容斥.详见代码: /****************************