Codeforces Round #589 (Div. 2) E. Another Filling the Grid(容斥+DP)

2024-04-18 06:32

本文主要是介绍Codeforces Round #589 (Div. 2) E. Another Filling the Grid(容斥+DP),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接:http://codeforces.com/contest/1228/problem/E

 

题目大意:一个n*n的正方形,每个格子能填1~k的数字,问每一行每一列至少有一个1的方案有几种

 

题目思路:

法一:

容斥,如果行和列一起容斥会很难,所以直接先保证列肯定全有,对行进行容斥,首先是所有列都有1的所有情况,第一列有1的情况就是k^i-(k-1)^i,随便取-取不到1的方案数就是至少有一个1的方案数,就是(k^i-(k-1)^i)^ni行n列,所有列都有1的所有情况,然后就开始容斥,-第一行没1的情况-第二行没1的情况-....+第一行没1和第二行没1的情况+第一行没1和第二行没2的情况.........就这么容斥下来,然后i从0到n遍历,表示有i行没有1的情况,然后就是\sum_{i=0}^{n}(-1)^i*\binom{n}{i}*(k-1)^{n*i}*(k^{n-i}-(k-1)^{n-i})^n

 

法二:

dp,dp[i][j]表示到第i行,有j列已经有1的方案数(保证前i行每行都有一个1),所以可以从dp[i-1][1~j]转移过来,如果dp[i-1][p](p<j)转移的话,那么就说明还需要添加j-p个1,已经有p行有1,那么就是从剩下n-p列中选择j-p个出来,那么除了这j行,其他的都不能选1,也就是(k-1)^{n-j},同时由于这j-p个一定要是1,所以原来的p个可以随便取,因为这p列已经有1了,在这个位置不是1也没事,所以就是k^p。如果等于j的话,那么就说明要继承原来列的情况,除了原来的列全都不能取1,也就是(k-1)^{n-j},原来那几列得保证这一行得出一个老哥保证这一行有一个1,所以就是k^j-(k-1)^j

 

以下是代码:

法一:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
const ll MAXN = 1e5+5;
const ll MOD = 1e9+7;
const ll maxn=1e6+10;
const ll mod=1e9+7;
ll fac[maxn],f[maxn],inv[maxn];void init()
{fac[0]=fac[1]=f[0]=f[1]=inv[0]=inv[1]=1;for(ll i=2;i<maxn;i++){fac[i]=fac[i-1]*i%mod;   // n!ll t=mod/i,k=mod%i;f[i]=(mod-t)*f[k]%mod;  // n的逆元inv[i]=inv[i-1]*f[i]%mod; // n!的逆元}
}ll C(ll n,ll m)
{if(n<m) return 0;return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll n,k;
ll a[MAXN];
ll powmod(ll x,ll y){ll rst=1;for(;y;y>>=1){if(y&1)rst=rst*x%MOD;x=x*x%MOD;}return rst;
}
int main()
{init();while(cin>>n>>k){rep(i,0,n){a[i]=(powmod(k,n-i)-powmod(k-1,n-i)+MOD)%MOD;}ll ans=0;rep(i,0,n){ll flag=1;if(i&1){flag=-1;}ll temp=C(n,i)*powmod(k-1,n*i)%MOD*powmod(a[i],n)%MOD;if(flag==-1){ans=(ans-temp+MOD)%MOD;}else ans=(ans+temp)%MOD;}cout<<ans<<endl;}return 0;
}

 

法二:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
const ll MAXN = 1e5+5;
const ll MOD = 1e9+7;
const ll maxn=1e6+10;
const ll mod=1e9+7;
ll fac[maxn],f[maxn],inv[maxn];void init()
{fac[0]=fac[1]=f[0]=f[1]=inv[0]=inv[1]=1;for(ll i=2;i<maxn;i++){fac[i]=fac[i-1]*i%mod;   // n!ll t=mod/i,k=mod%i;f[i]=(mod-t)*f[k]%mod;  // n的逆元inv[i]=inv[i-1]*f[i]%mod; // n!的逆元}
}ll C(ll n,ll m)
{if(n<m) return 0;return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll n,k;
ll dp[300][300];
ll a1[300];
ll a2[300];
int main()
{init();while(cin>>n>>k){a1[0]=a2[0]=1;rep(i,1,250){a1[i]=a1[i-1]*(k-1)%MOD;a2[i]=a2[i-1]*k%MOD;}memset(dp,0,sizeof(dp));rep(i,1,n)dp[1][i]=C(n,i)*a1[n-i]%MOD;rep(i,2,n){rep(j,1,n){rep(p,1,j){if(p==j)dp[i][j]=(dp[i][j]+dp[i-1][j]*a1[n-j]%MOD*(a2[j]-a1[j]+MOD)%MOD)%MOD;else dp[i][j]=(dp[i][j]+dp[i-1][p]*C(n-p,j-p)%MOD*a1[n-j]%MOD*a2[p]%MOD)%MOD;}}}cout<<dp[n][n]<<endl;}return 0;
}

 

这篇关于Codeforces Round #589 (Div. 2) E. Another Filling the Grid(容斥+DP)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/914008

相关文章

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs

uva 10069 DP + 大数加法

代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <cl

uva 10029 HASH + DP

题意: 给一个字典,里面有好多单词。单词可以由增加、删除、变换,变成另一个单词,问能变换的最长单词长度。 解析: HASH+dp 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc