zoukankan      html  css  js  c++  java
  • NOIP模拟题——LGTB与桌子

    LGTB新买了一张n*m的矩(桌)阵(子),他想给某些1*1的小矩形染色,使得染色之后,原矩阵的每个n*n的子矩阵中都包含恰好k个被染色了的小矩形。他想知道有多少种染色方案能让他满足上述要求。因为答案肯呢个很大,请输出方案数膜1e9+7的值

    输入

    输入第一行包含三个整数n,m,k,意义如题面所示

    对于15%的数据,1≤n*m≤20,n≤m

    对于40%的数据,1≤n≤10,n≤m≤1000

    对于100%的数据,1≤n≤100,n≤m≤1e18,0≤k≤n²

    输出

    输出包含1个整数,代表LGTB的方案数

    样例

    样例输入

    5 6 1

    样例输出

    45

    时间限制

    3s

    样例说明

    样例如图所示,如果在灰色区域染一个格子,有20种方案。如果在两边的白色格子各染一个格子,有25种方案。共45种方案。

    由于题目描述中m最大是1e18,所以肯定要用到快速幂。

    首先我们可以发现,如果把一列捆在一起处理的话,那么为了满足题意,第i列一定与第i+n列的染色个数是相同的。

    那么考虑DP[i][j],代表每一个整个块(如1~n为一块,n+1~2*n为一块,因为他们每一列的染色个数相同)中处理了前i列,此时染了j个颜色的方案数。

    那么如果考虑下一块的话,设下一块染色个数为kk,则增加的方案数就为C[n][k]^t[i](t[i]为i位置存在的总个数)

    于是C[n][k]用杨辉三角求出,然后在快速幂求C[n][k]^t[i]。

    这里会发现,有可能最后要多出一点,也就是部分块,那么他们的列数要+1。

    处理完过后,就可以直接DP了。时间复杂度O(n^4)

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cmath>
     5 using namespace std;
     6 const int maxn=105;
     7 const long long mod=1e9+7;
     8 int n,k;long long m;
     9 long long c[maxn][maxn];
    10 long long dp[maxn][maxn*maxn];
    11 long long w[2][maxn];long long re;
    12 long long qe(long long a,long long b)
    13 {
    14     long long qwe=1;
    15     while(b)
    16     {
    17         if(b&1)qwe*=a;
    18         if(qwe>mod)qwe%=mod;
    19         b>>=1;a=a*a;
    20         if(a>mod)a%=mod;
    21     }
    22     return qwe;
    23 }
    24 void init()
    25 {
    26     c[0][0]=1;
    27     for(int i=1;i<=100;i++)
    28     for(int j=0;j<=i;j++)
    29     {
    30         c[i][j]=c[i-1][j]+c[i-1][j-1];
    31         if(c[i][j]>mod)c[i][j]%=mod;
    32     }
    33     long long qwe=m/n;
    34     re=m%n;
    35     for(int i=0;i<=n;i++)
    36     {
    37         w[0][i]=qe(c[n][i],qwe);
    38         w[1][i]=qe(c[n][i],qwe+1);
    39     }
    40     return ;
    41 }
    42 int main()
    43 {
    44     freopen("table.in","r",stdin);
    45     freopen("table.out","w",stdout);
    46     scanf("%d%I64d%d",&n,&m,&k);
    47     init();
    48     dp[0][0]=1;
    49     long long wer=0;
    50     for(int i=0;i<n;i++)//
    51     for(int j=0;j<=n*i;j++)
    52     for(int kk=0;kk<=min(n,k);kk++)
    53     {
    54         if(i<re)//多了一列 
    55         wer=w[1][kk];
    56         else wer=w[0][kk];
    57         
    58         dp[i+1][j+kk]+=wer*dp[i][j]%mod;
    59         dp[i+1][j+kk]%=mod;
    60     }
    61     printf("%I64d",dp[n][k]);
    62     return 0;
    63 }

     

  • 相关阅读:
    sql中保留2位小数
    C# 操作字符串,在某些特定的字符后面或前面添加其它字符
    Windows Server 2008 R2中上传和下载文件
    winform中显示标题,点击打开链接
    正则表达式
    winform重绘
    js获取元素的页面坐标
    剑指offer-从上往下打印二叉树
    剑指offer-栈的压入、弹出序列
    剑指offer-包含min函数的栈
  • 原文地址:https://www.cnblogs.com/937337156Zhang/p/6070381.html
Copyright © 2011-2022 走看看