CF 组合数学整理
懒得更新。
CF 267 E
我们只需要求出有序的方案数
首先
一个位置不能同时放多个左端点或多个右端点,因此,只有四种情况:不放,放一个左端点,放一个右端点,放一个左端点一个右端点。
注意到,如果你放完了左端点和右端点,对应唯一一个方案(不能包含)。
设
Code
#include <bits/stdc++.h>
using namespace std;
#define de(x) cout<<#x<<"="<<x<<endl
using ll = long long;
const int N = 330;
const int mod = 1e9+7;
int n,m,x;
ll fac[N],dp[2][N][N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>x;
if (n>m){
cout<<0<<endl;
return 0;
}
fac[0]=1;
for (int i=1; i<N; i++){
fac[i]=fac[i-1]*i%mod;
}
dp[0][0][0]=1;
for (int i=1; i<=m; i++){
int cur=i&1;
int pre=cur^1;
for (int j=0; j<=n; j++){
for (int k=0; k<=j; k++){
dp[cur][j][k]=0;
if (j && k){
(dp[cur][j][k]+=dp[pre][j-1][k-1])%=mod;
}
if (j && j-1>=k){
(dp[cur][j][k]+=dp[pre][j-1][k])%=mod;
}
if (i!=x){
if (k){
(dp[cur][j][k]+=dp[pre][j][k-1])%=mod;
}
(dp[cur][j][k]+=dp[pre][j][k])%=mod;
}
// cout<<i<<","<<j<<","<<k<<":"<<dp[cur][j][k]<<endl;
}
}
}
// cout<<fac[n]<<endl;
cout<<dp[m&1][n][n]*fac[n]%mod<<endl;
return 0;
}
// don't waste time!!!
CF 140 E
设
设
Code
#include <bits/stdc++.h>
using namespace std;
#define de(x) cout<<#x<<"="<<x<<endl
using ll = long long;
const int N = 5e3+3;
const int M = 1e6+6;
ll n,m,mod;
ll l[M],fac[N],A[N];
ll cnt[N][N],dp[2][N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>mod;
for (int i=1; i<=n; i++){
cin>>l[i];
}
fac[0]=1;
for (int i=1; i<N; i++){
fac[i]=fac[i-1]*i%mod;
}
A[0]=1;
for (int i=1; i<N; i++){
A[i]=A[i-1]*(m-i+1)%mod;
}
cnt[0][0]=1;
for (int i=1; i<N; i++){
for (int j=1; j<=min(i*1ll,m); j++){
cnt[i][j]=(cnt[i-1][j-1]+cnt[i-1][j]*(j-1)%mod)%mod;
}
}
ll sum=1;
for (int i=1; i<=n; i++){
int cur=i&1;
for (int j=1; j<=l[i]; j++){
dp[cur][j]=A[j]*cnt[l[i]][j]%mod*sum%mod;
(dp[cur][j]+=mod-fac[j]*cnt[l[i]][j]%mod*dp[cur^1][j]%mod)%=mod;
}
sum=0;
for (int j=1; j<=l[i]; j++){
(sum+=dp[cur][j])%=mod;
}
memset(dp[cur^1],0,sizeof dp[0]);
}
cout<<sum<<endl;
return 0;
}
// don't waste time!!!
CF 518 F
分类讨论拐几次。
-
零次:直接枚举行或列。
-
一次:枚举“转折点”。
-
两次:预处理
分别代表从哪个方向来能不能延申到 。有两次转折,一定是两条横加上一个竖或者反之。对于一条横的情况:枚举是那一条横。从左到右枚举竖的地方。考虑先设 。(初始)对于 : , 因为不能两条竖线相邻, ,若 , 。其实, 就是当前的前面可以与它匹配的方案数。另一种情况同理。
三种答案加起来即可。
Code
#include <bits/stdc++.h>
using namespace std;
#define de(x) cout<<#x<<"="<<x<<endl
using ll = long long;
const int N = 2e3+3;
ll n,m,u[N][N],d[N][N],l[N][N],r[N][N],ans;
char s[N][N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for (int i=0; i<n; i++){
for (int j=0; j<m; j++){
cin>>s[i][j];
u[i][j]=d[i][j]=l[i][j]=r[i][j]=(s[i][j]=='.');
s[i][j]=(s[i][j]=='.');
}
}
for (int i=1; i<n; i++){
for (int j=0; j<m; j++){
u[i][j]&=u[i-1][j];
}
}
for (int i=0; i<n; i++){
for (int j=1; j<m; j++){
l[i][j]&=l[i][j-1];
}
}
for (int i=n-2; i>=0; i--){
for (int j=m-1; j>=0; j--){
d[i][j]&=d[i+1][j];
}
}
for (int i=n-1; i>=0; i--){
for (int j=m-2; j>=0; j--){
r[i][j]&=r[i][j+1];
}
}
for (int i=1; i<n-1; i++){
int fl=1;
for (int j=0; j<m; j++){
fl&=s[i][j];
}
ans+=fl;
}
for (int i=1; i<m-1; i++){
int fl=1;
for (int j=0; j<n; j++){
fl&=s[j][i];
}
ans+=fl;
}
for (int i=1; i<n-1; i++){
for (int j=1; j<m-1; j++){
ans+=(u[i][j]+d[i][j])*(l[i][j]+r[i][j]);
}
}
for (int i=1; i<n-1; i++){
int sum=u[i][1]+d[i][1];
for (int j=2; j<m-1; j++){
ans+=sum*(u[i][j]+d[i][j])-u[i][j]*u[i][j-1]-d[i][j]*d[i][j-1];
sum+=u[i][j]+d[i][j];
if (!s[i][j]){
sum=0;
}
}
}
for (int j=1; j<m-1; j++){
int sum=l[1][j]+r[1][j];
for (int i=2; i<n-1; i++){
ans+=sum*(l[i][j]+r[i][j])-l[i][j]*l[i-1][j]-r[i][j]*r[i-1][j];
sum+=l[i][j]+r[i][j];
if (!s[i][j]){
sum=0;
}
}
}
cout<<ans<<endl;
return 0;
}
// don't waste time!!!
CF 660 E
求出每一个子序列在
-
若
, 为空,那么每一个 中的序列都包含,给答案贡献 。 -
若
,对于一个确定的序列,设 出现的位置为 考虑:第 个位置往后,可以随便填, ;从前 个位置选 个放 , ;为了避免重复,前 个位置不放 中的数的,每个数有 个取法, 。因此答案贡献 。
答案是
Code
#include <bits/stdc++.h>
using namespace std;
#define de(x) cout<<#x<<"="<<x<<endl
using ll = long long;
const int N = 1e6+6;
const ll mod = 1e9+7;
ll n,m,ans,x[N],y[N];
void init(){
x[0]=1;
y[0]=1;
for (int i=1; i<=n; i++){
x[i]=x[i-1]*m%mod;
y[i]=y[i-1]*(2*m-1)%mod;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
init();
for (int i=1; i<=n; i++){
(ans+=x[n-i+1]*y[i-1]%mod)%=mod;
}
(ans+=x[n])%=mod;
cout<<ans<<endl;
return 0;
}
// don't waste time!!!
CF 40 E
考虑无解的情况。一个解中所有数的积不仅是
所以,答案就是:对于所有的行,其中一个空的行扔掉,其他的行,如果填完了,
Code
#include <bits/stdc++.h>
using namespace std;
#define de(x) cout<<#x<<"="<<x<<endl
using ll = long long;
const int N = 1e3+3;
int n,m,k,mod;
int cnt[N],it[N];
ll pw(ll x,ll y){
if (y<0){
return 1;
}
ll res=1;
while (y){
if (y&1){
res=res*x%mod;
}
x=x*x%mod;
y>>=1;
}
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>k;
bool f=0;
if (n<m){
f=1;
swap(n,m);
}
for (int i=1; i<=n; i++){
cnt[i]=m;
it[i]=1;
}
for (int i=0; i<k; i++){
int a,b,c;
cin>>a>>b>>c;
if (f){
swap(a,b);
}
cnt[a]--;
it[a]*=c;
}
if (n%2!=m%2){
cout<<0<<endl;
return 0;
}
cin>>mod;
f=0;
ll res=1;
for (int i=1; i<=n; i++){
if (cnt[i]==0 && it[i]==1){
cout<<0<<endl;
return 0;
}
if (cnt[i]==m && !f){
f=1;
continue;
}
else{
res=res*pw(2,cnt[i]-1)%mod;
}
}
cout<<res<<endl;
return 0;
}
// don't waste time!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下