P5135 painting 大整数 排列组合

探讨在N×M网格图上,根据严格下降或非上升条件,绘制包含每一列恰好一个黑格子的不同图案的数量。使用组合数学原理和编程技巧解决这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目背景 https://www.luogu.org/problemnew/show/P5135

Wolfycz很喜欢画画(雾

题目描述

Wolfycz喜欢网格图,他希望在网格图上画上一些黑格子,使得每一列都恰好有一个黑格子。但是黑格子太乱了不好看,所以Wolfycz希望黑格子按列号依次连线是下降的,具体来讲,每列黑格子所在行号不得小于前一列黑格子所在行号(我们令左上角为第一行第一列)

Wolfycz觉得这样画出来的图非常漂亮,但是Wolfycz有时候觉得连线要严格下降才好看(即每列黑格子所在行号必须大于前一列黑格子所在行号),有时候觉得连线只要不上升就好看(即每列黑格子所在行号不得小于前一列黑格子所在行号)。现在Wolfycz想知道,对于一个N×MN×MN×M的网格图,他能画出多少个好看的图?两个图不相同,当且仅当存在某一列的黑格子,它在两个图中对应的行号不同

UPD:NNN行MMM列

输入输出格式

输入格式:

 

第一行读入TTT,表示有TTT组数据

接下来每一行读入三个整数N,M,optN,M,optN,M,opt,表示N×MN×MN×M的矩阵,如果optoptopt为1,则Wolfycz认为连线要严格下降才好看;如果optoptopt为0,则Wolfycz认为连线只要不上升就好看

 

输出格式:

 

输出共TTT行,每行一个整数,表示Wolfycz能画出不同的图的个数,答案对10^9+7取模

 

输入输出样例

输入样例#1: 复制

5
5 2 1
5 3 0
3 4 0
8 4 1
6 2 1

输出样例#1: 复制

10
35
15
70
15

 

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1;char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=1e6,p=1e9+7;
int inv[N+10];
int C(ll n,int m){
    if (n<m)    return 0;
    int res=1;
    for (int i=1;i<=m;i++)  res=1ll*res*((n-i+1)%p)%p*inv[i]%p;
    return res;
}
int main(){
    inv[1]=1;
    for (int i=2;i<=N;i++)  inv[i]=1ll*(p-p/i)*inv[p%i]%p;
    for (int Data=read();Data;Data--){
        ll n; int m,opt;
        scanf("%lld%d%d",&n,&m,&opt);
        printf("%d\n",opt?C(n,m):C(n+m-1,m));
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值