• B


    Time Limit : 1 Second      Memory Limit : 65536 KB

    Source : 第十届山东省ACM省赛

    Problem Link : ZOJ 4114

    Author : Houge  Date : 2019-5-21

     

    题目大意:

      给你一排n个灯泡,让你进行k轮操作,每轮操作可以点亮或熄灭m个不同的灯泡。然后给你这排灯泡的初态和末态,问你在k轮操作后能让这排灯泡到达末态的方案有多少种(对998244353取模)。

    分析:

      DP,学习了点我跳转XD的代码和思路。这个题我们在比赛的时候也想过用dp,不过主攻dp的我太菜了写不出状态转移方程,汗颜啊。。。

      先来考虑状态转移方程:

      ·我们可以这样想:对于同一个灯泡来说,如果它初态和末态的状态一样,那么可以认为在这个过程中它被操作了偶数次,反之则认为它被操作了奇数次,可以用odd_num来记录奇数次操作的灯泡的个数。

      ·然后我们声明一个二维数组dp[i][j],代表经过i轮操作过后有j个灯泡被操作了奇数次的方案数。

      ·接着我们来想一下它的下一轮操作:从j个奇数次操作的灯泡中选出k个,使它们变成偶数次操作;然后偶数次操作的灯泡中会有m-k个灯泡变成奇数次操作,即下一个状态为:dp[i+1][j-k+m-k]。

      ·最后利用组合数便可得到状态转移方程:

        (注意要取模)

      然后再来考虑一下初值的问题:

      ·对于dp中所有元素的初值,可先赋值为0。

      ·对于初态和末态,第一种方法是将初态设为dp[0][0]=1,最后输出末态dp[k][odd_num],但这样会有一个问题,初态是明确的,但是末态时虽然奇数次操作灯泡的个数时对的,但是并不能确定是哪几个灯泡,会有错误(*经过测试应该会输出oddnum个数的所有方案和)。

      ·所以有了第二种方法,将初态设为dp[0][odd_num]=1,最后输出的是dp[k][0],这样初末态就都明确了。

       最后考虑几个细节问题:

      ·推荐用long long,因为最后答案比较大随时可能爆掉(未测试)。

      ·在计算时随时取模防止爆。

      ·在求组合数的时候也要取模(我在后来自己写的时候就是这个地方卡住了,最后还是看的题解才发现的)。

      到这儿这个问题就基本解决了~

    代码:

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int MAXN=105,MOD=998244353;
     6 long long c[MAXN][MAXN],dp[MAXN][MAXN];
     7 
     8 int main()
     9 {
    10     long long i,j,k;
    11     for(i=0;i<MAXN;i++)    //求组合数
    12         for(j=0;j<=i;j++) c[i][j]=1;
    13     for(i=2;i<MAXN;i++)
    14         for(j=1;j<i;j++)
    15             c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD;    //要取模!
    16 
    17     int t;
    18     scanf("%d",&t);
    19     while(t--)
    20     {
    21         memset(dp,0,sizeof(dp));    //初始化
    22         long long n,r,m,oddnum=0;
    23         char curr[MAXN],dist[MAXN];
    24         scanf("%lld%lld%lld%s%s",&n,&r,&m,curr,dist);
    25 
    26         for(i=0;i<n;i++)
    27             if(curr[i]!=dist[i]) oddnum++;
    28 
    29         dp[0][oddnum]=1;
    30 
    31         for(i=0;i<r;i++)    //dp
    32             for(j=0;j<=n;j++)
    33                 for(k=0;k<=m;k++)
    34                 {
    35                     if(j>=k&&n-j>=m-k)    
    36                     {
    37                         dp[i+1][j-k+m-k]=dp[i+1][j-k+m-k]+(dp[i][j]*c[j][k]%MOD*c[n-j][m-k]%MOD);
    38                         dp[i+1][j-k+m-k]%=MOD;
    39                     }
    40                 }
    41         printf("%lld
    ",dp[r][0]);
    42     }
    43     return 0;
    44 }
  • 相关阅读:
    POJ2503 Babelfish
    POJ3687 Labeling Balls(拓扑)
    POJ2251 Dungeon Master(bfs)
    POJ1321 棋盘问题(dfs)
    POJ3009 Curling 2.0(DFS)
    POJ2248 A Knight's Journey(DFS)
    POJ3080 Blue Jeans
    POJ1260 Pearls(dp,矩阵链乘法)
    POJ3349 Snowflake Snow Snowflakes(哈希)
    POJ2479 Maximum sum(dp)
  • 原文地址:https://www.cnblogs.com/CSGOBESTGAMEEVER/p/10900928.html
Copyright © 2020-2023  润新知