放棋子

放棋子

  • 看到题目后显然先想到 DP ,但是 N200 ,那就肯定不行了。

  • 题目理解:障碍与棋子一样,都是每行,列只有一个,因此,我们思考这样一个问题:

10001000001001000100001000010001

    这两种情况的方案数有何区别?

  • 答案是并无区别:显然第一种矩阵经过行与行(或列于列)的变换就能转化为第二种,而每一行每一列都会有一个障碍,因此,每一种矩阵都能转化为第二种,转化后每一行(或列)的方案数不变,总方案数当然也不变。

  • 因此我们不考虑输入的矩阵,直接转化为第一种,认为障碍均在对角线上,于是,原问题就成了:在一个对角线不可放的棋盘放棋子,且每一列,每一行均只有一枚棋子。

  • 进一步转化,问题就成了:一个数列 an(aii) 求方案数,这就是一个裸的错排问题了,例题:信封问题,没做过的同学可以自行了解一下,这里直接给出递推式:

f1=0f2=1fn=(n1)×(fn1+fn2)

  • 考虑到 fn 的增长速率极快,需要高精度辅助实现。

#include<bits/stdc++.h>
#define ll long long
const ll p=10000000000000000;
const int len=100010;
ll f[201][len],tem,pos;
void work(int n){
    for(int i=1;i<=len;++i){
        tem=f[n-1][i]+f[n-2][i];
        f[n][i]=(tem+pos)%p;
        pos=tem/p;
    }
    for(int i=1;i<=len;++i){
        tem=f[n][i]*(n-1);
        f[n][i]=(tem%p+pos);
        pos=tem/p;
    }
}
int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j){
            int a;scanf("%d",&a);
        }没什么用的输入
    if(n==1) return puts("0"),0;
    if(n==2) return puts("1"),0;
    f[1][1]=0;f[2][1]=1;
    for(int i=3;i<=n;++i) work(i);
    int len1(100010);
    while(f[n][len1]==0&&len1>1) len1--;
    printf("%lld",f[n][len1]);
    while(--len1) printf("%016lld",f[n][len1]);
}

码风丑陋,见谅!

posted @   Melting_Pot  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示