首页 > 其他分享 >P5059 中国象棋

P5059 中国象棋

时间:2023-11-12 21:35:13浏览次数:21  
标签:中国象棋 P5059 int ret ans inline dp mod

由题意可知,首先将 \(n+1\) 。
每一行显然是互不干扰的,所以最终的答案就是第一行答案 \(ans\) 的 \(n\) 次方。

下面考虑如何求第一行的答案。

首先,如果一次将两个限制都考虑进去,那么有一个显然的 dp,设 \(dp_{i,j,k}\) 表示第 \(i\) 个格子的状态为 \(k\) ,\(k\) 为 \(1\) 表示这个格子有棋子,\(0\) 则表示没有,前 \(i\) 个格子填了 \(j\) 个棋子的方案数。但这样是不可做的。
接下来,考虑只有第二个限制。有 \(dp_{i,k}\) ,就是省去前面第二维的 dp 式子。那么转移就是 $$dp_{i,0}=dp_{i-1,0}+dp_{i-1,1}$$ $$dp_{i,1}=dp_{i-1,0}$$
设 \(ans_i\) 表示仅考虑前 \(i\) 个格子的方案数(不考虑第一个限制的情况下),有 $$ans_{i-1}=dp_{i,0}$$ $$ans_i=dp_{i,0}+dp_{i,1}=2\times dp_{i-1,0}+dp_{i-1,1}=ans_{i-1}+dp_{i-1,0}=ans_{i-1}+ans_{i-2}$$
然后加入第一个限制,设 \(Ans_i\) 表示前 \(i\) 个格子真正的方案数,显然就是从 \(ans_i\) 里减去只放一个棋子和不放的方案数,则$$Ans_i=ans_i-(i+1)$$
现在就可以得到第一行的最终答案 \(Ans_n=ans_n-(n+1)\) ,而其中的 \(ans_n\) 显然可以通过矩阵快速幂求出。
最后总的答案就是 \(Ans_n^n\) ,进行快速幂求解即可。

#include<bits/stdc++.h>
#define int __int128
using namespace std;

inline int rd()
{
    int ret=0;
    char c=getchar();
    for (;!isdigit(c);c=getchar());
    for (; isdigit(c);c=getchar()) ret=ret*10+(c-'0');
    return ret;
}
inline void wr(int x)
{
    if (!x) return putchar('0'),void();
    short pt[100],tp=0;
    for (;x;x/=10) pt[++tp]=x%10;
    for (;tp;tp--) putchar(pt[tp]^48);
}

int n,mod,ans,d;
inline int add(int x) {return x%mod;}

struct Matrix1{
    int a[2];
    inline void init() {a[0]=a[1]=0;}
    int& operator[](int x) {return a[x];}
}bas;
struct Matrix2{
    int a[2][2];
    inline void init() {memset(a,0,sizeof a);}
    Matrix1 operator*(const Matrix1& b)const{
        Matrix1 c;
        c.init();
        for (int i=0;i<2;i++)
            for (int j=0;j<2;j++) c.a[i]=add(c.a[i]+a[i][j]*b.a[j]%mod);
        return c;
    }
    Matrix2 operator*(const Matrix2& b)const{
        Matrix2 c;
        c.init();
        for (int i=0;i<2;i++)
            for (int j=0;j<2;j++)
                for (int k=0;k<2;k++) c.a[i][j]=add(c.a[i][j]+a[i][k]*b.a[k][j]%mod);
        return c;
    }
}tmp;

inline void ksm(int b)
{
    while (b)
    {
        if (b&1) bas=tmp*bas;
        tmp=tmp*tmp;
        b>>=1;
    }
}

inline int ksm(int a,int b)
{
    int ret=1;
    while (b)
    {
        if (b&1) ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}

signed main()
{
    n=rd(),mod=rd();
    n++;
    if (n==1) ans=0;
    else if (n==2) ans=0;
    else
    {
        bas[0]=3,bas[1]=2;
        tmp.a[0][0]=tmp.a[0][1]=tmp.a[1][0]=1;
        tmp.a[1][1]=0;
        ksm(n-2);
        ans=bas.a[0];
        ans=add((ans-n-1)%mod+mod);
    }
    wr(ksm(ans,n));
}

这题其实最难的地方是在想到要一个个的满足限制,想到了这里,后面的就很简单了。

标签:中国象棋,P5059,int,ret,ans,inline,dp,mod
From: https://www.cnblogs.com/Fredericm/p/LuoguP5059.html

相关文章

  • Python pygame实现中国象棋单机版源码
    今天给大家带来的是关于Python实战的相关知识,文章围绕着用Pythonpygame实现中国象棋单机游戏版展开,文中有非常详细的代码示例,需要的朋友可以参考下#-*-coding:utf-8-*-"""CreatedonSunJun1315:41:562021@author:Administrator"""importpygamefrompygame.local......
  • 中国象棋程序的设计与实现(二)--源码
    本篇将正式公布中国象棋程序–高级版–楚汉棋兵的所有源码。介绍一些相关信息,如源码下载地址、QQ交流群、源码结构、版权声明。其它更多文档,如毕业设计论文、项目架构图图、心得体会、开发记录,将在本月全部公布。有兴趣的同学,可以趁着中秋节3天、国庆7天等假期,进行研究。我也将......
  • P2051 [AHOI2009] 中国象棋 题解
    DP。状态设计是点睛之笔。首先显然有每行或每列只能有至多\(2\)个棋子。设状态\(f_{i,j,k}\)为第\(i\)行,有\(j\)列只放了一个棋子,\(k\)列放了两个棋子。之后直接转移即可。注意边界判断。code:点击查看代码#include<bits/stdc++.h>#definelllonglong#defined......
  • [AHOI2009] 中国象棋 题解
    每行每列的炮数量\(\leq2\),那么整个图就可以被分解为一些环和链。考虑答案的二元生成函数,显然环和链分别的生成函数都是平凡的多项式,而答案的多项式无非是加起来后求exp......
  • 使用 HTML、CSS 和 JS 制作一个中国象棋
    ......
  • 编程之美 - 1.2 中国象棋的将帅问题
    问题导读:在一把象棋的残局中,象棋双方的将帅不可以相见,即不可以在中间没有其他棋子的情况下在同一列出现。而将、帅各被限制在己方的3*3的格子中运动。相信大家都非常熟悉象......
  • P2051中国象棋
    题目链接:戳这里题目大意:\(①\)给你一个\(n*m\)的棋盘\(②\)问你有多少种放炮的方案使得炮不会相互攻击\(③\)炮的规则和中国象棋一样前置知识:\(①\)首先你需......
  • NC19885 [AHOI2009]CHESS 中国象棋
    题目链接题目题目描述在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。请问有多少种放置方法,中国像棋中炮的行走方式大家应该很清楚吧.一个......