一、状态设计和简化(状態をまとめる)

例题1:Unhappy Hacking

题意

有一个空串,可以进行下面三种操作:

  • 在末尾加入一个 \(0\)。
  • 在末尾加入一个 \(1\)。
  • 删去末尾的数,如果串为空则忽略。

求 \(n\) 次操作后满足整个串等于某个给定的串 \(S\) 的方案数模 \(10^9+7\)。\(n,|S|\le 5\times 10^3\)。

解法1(本人的 ** 解法)

某次操作可以删去原有匹配好的串的一部分,考虑消除这种操作带来的影响。

此时可以对于每个 \(i\),在填好的串为最后一次和长度为 \(i\) 的前缀相同的时候进行统计。显然之后的操作不包括将前 \(i\) 个字符删除,所以在最后一次匹配长度为 \(i+1\) 的前缀时,一定只会删去新加的字符然后加入一个对应的字符。这两次匹配之间加入/删除的操作可以形成一个合法的括号序列。设 \(dp_{i,j}\) 为进行了 \(i\) 次操作,形成了长度为 \(j\) 的前缀的方案数,则转移为 \(dp_{i,j}=\sum\limits_{k=0}^{\lfloor\frac{i-1}2\rfloor}dp_{i-2k-1,j-1}2^k\frac{\binom{2k}{k}}{k+1}\),(其中 \(\frac{\binom{2k}{k}}{k+1}\) 为长为 \(2k\) 的合法括号序列数,也就是 卡塔兰数)是一个卷积的形式,可以使用 MTT + 快速幂解决。(懒得写。)

注意 \(dp_{i,0}\) 需要 \(O(n^2)\) 特别计算(可能对空串进行删除操作)。

解法2(题解区首页解法

考虑只在删除操作处计算对应的贡献。显然我们只关心未被删除的部分能否构成 \(S\),此时如果某个插入/删除序列中有 \(k\) 次删除操作删除了某个数,则其对应了 \(2^k\) 种实际方案。

设 \(dp_{i,j}\) 为进行了 \(i\) 次操作,得到了长为 \(j\) 的串的方案数。如果下一次操作为删除,则 \(dp_{i,j}\gets 2dp_{i-1,j+1}\)(特别的,\(dp_{i,0}\gets dp_{i-1,0}\));如果下一次操作为加入,则 \(dp_{i,j}\gets dp_{i-1,j-1}\)(\(j>0\))。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=5010;
const int md=1000000007;
int n,m,i,j,b,dp[2][maxn],*X=dp[0],*Y=dp[1]; char s[maxn];
inline int Plus(int x,int y){return x-=((x+=y)>=md)*md;}
int main(){
scanf("%d%s",&n,s+1);
m=strlen(s+1); dp[1][0]=1;
for(i=1;i<=n;++i){
swap(X,Y); Y[0]=Plus(X[0],Plus(X[1],X[1]));
for(j=1;j<=i;++j) Y[j]=Plus(X[j-1],Plus(X[j+1],X[j+1]));
}
printf("%d",Y[m]);
return 0;
}

例题2:Road of the King

题意

有一个 \(n\) 个点的图,目前一条边都没有。

有一个人在 \(1\) 号点要进行 \(m\) 次移动,终点不必是 \(1\) 号点,假设第 \(i\) 次从 \(u\) 移动到 \(v\),那么在 \(u\) 与 \(v\) 之间连一条有向边。可以有 \(u=v\)。

问有多少种序列能满足:最终 \(n\) 个点组成的图是一个强连通图。答案对 \(10^9+7\) 取模。\(n,m\le 300\)。

解法

考虑形成强连通图的一个充要条件:对于某个点 \(u\),满足所有点都能从 \(u\) 到达,所有点也都有到达 \(u\) 的路径。所以在构造时,令 \(u=1\),则每次回到 \(1\) 之后均会使得之前从 \(1\) 出发能到达的点现在能到达 \(1\)。(显然只需要考虑之前不能到达 \(1\) 的点)

设 \(dp_{i,j,k}\) 为在第 \(i\) 次操作时,目前有 \(j\) 个点能到达 \(1\),而距上次从 \(1\) 出发已经经过了 \(k\) 个不能到达 \(1\) 的点。转移时考虑从当前点能走到哪个点。如果走到了已经经过的 \(k\) 个点,则 \(dp_{i+1,j,k}\gets k\times dp_{i,j,k}\);如果走到了还没有经过的 \(n-j-k\) 个点,则 \(dp_{i+1,j,k+1}\gets (n-j-k)\times dp_{i,j,k}\);如果走到了能到达 \(1\) 的 \(j\) 个点,则 \(dp_{i+1,j+k,0}\gets j\times dp_{i,j,k}\)。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=310;
const int md=1000000007;
int n,m,i,j,k,b,c,w;
int dp[2][maxn][maxn];
int main(){
scanf("%d%d",&n,&m);
auto X=dp[0],Y=dp[1]; X[1][0]=1;
for(i=1;i<=m;++i){
for(j=1,b=n-1;j<=n;++j,--b){
for(k=0,c=b;k<=b;++k,--c){
w=X[j][k];
Y[j][k]=(1LL*k*w+Y[j][k])%md;
Y[j][k+1]=(1LL*c*w+Y[j][k+1])%md;
Y[j+k][0]=(1LL*j*w+Y[j+k][0])%md;
}
}
swap(X,Y); memset(Y,0,sizeof(dp[0]));
}
printf("%d",X[n][0]);
return 0;
}

例题3:Hakone

题意

有一个 \(1\sim n\) 的排列 \(P\)。现在对于每个 \(i\),给出 \(P_i\) 和 \(i\) 的大小关系(\(P_i>i/P_i=i/P_i<i\)),求可能的 \(P\) 的数量模 \(10^9+7\)。\(n\le 200\)。

解法

考虑建一张二分图,第 \(i\) 个左部点向所有可能的 \(P_i\) 的取值的右部点连边,则问题变成了求该二分图的最大匹配数。显然可以删去所有满足 \(P_i=i\) 的对应 \(i\),则之后的每个 \(P_i\ne i\),方便之后的讨论。

显然无论单独看哪一部分的点,钦定每个点匹配的点时都会十分困难(无法确定其对之后的影响)。考虑每次同时处理第 \(i\) 个左部点/右部点,且对于一对匹配点,只在编号更大的点统计贡献(避免后效性)。设 \(dp_{i,j,k}\) 为考虑了前 \(i\) 对点,且 \(j\) 个左部点和 \(k\) 个右部点未匹配的方案数(显然 \(j\) 个左部点只向编号更大的右部点连边)。如果 \(P_{i+1}>i+1\),则该左部点只能向编号更大的右部点连边,\(dp_{i+1,j+1,k+1}\gets dp_{i,j,k}\);否则其需要向编号更小的右部点连边,\(dp_{i+1,j,k}\gets k\times dp_{i,j,k}\)。注意右部点可能和之前的 \(j\) 个左部点之一匹配,可能不匹配,所以还有 \(dp_{i+1,j,k}\gets j\times dp_{i,j,k}\),\(dp_{i+1,j-1,k-1}\gets j\times k\times dp_{i,j,k}\)。注意到合法的 dp 状态一定满足 \(j=k\),所以可以合并后两维。

代码

注意某些日本远古题需要文末换行。

点此查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=210;
const int md=1000000007;
int n,i,j,t; char ch; bool p[maxn];
int dp[2][maxn],*X=dp[0],*Y=dp[1];
int main(){
scanf("%d",&n);
while(n--){
scanf(" %c",&ch);
if(ch=='-') continue;
p[++t]=(ch=='U');
}
X[0]=1;
for(i=0;i<t;++i,swap(X,Y)){
for(j=0;j<=i;++j) Y[j]=(1LL*X[j]*j)%md;
if(p[i+1]) for(j=0;j<=i;++j) Y[j+1]-=((Y[j+1]+=X[j])>=md)*md;
else for(j=1;j<=i;++j) Y[j-1]=(((1LL*j*j)%md)*X[j]+Y[j-1])%md;
}
printf("%d\n",X[0]);
return 0;
}

二、设计转移顺序(探索順の変更)

1. 降序枚举(大きい順に並べる)

例题1:My friends are small

题意

有一个长为 \(n\) 的数组 \(w\)。设 \(S\) 为 \(w\) 的一个子集,求满足 \(\min_{i\not\in S}i>W-\sum_{i\in S}i\) 的所有 \(S\) 的数量模 \(10^9+7\)。\(n\le 200;w_i,W\le 10^4\)。

解法

考虑枚举每个最小值对应的方案。此时一定需要选择小于最小值的所有数,不能选择最小值,然后选择另外一些大于最大值的数。此时可以从大到小枚举每个最大值,使用背包维护对应方案数。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=210;
const int maxm=10010;
const int md=1000000007;
int n,i,j,k,s,a,v,W,w[maxn],dp[maxm];
inline void Add(int &x,int y){x-=((x+=y)>=md)*md;}
int main(){
scanf("%d%d",&n,&W);
for(i=1;i<=n;++i) scanf("%d",w+i),s+=w[i];
sort(w+1,w+n+1); dp[0]=1;
if(s-w[n]<=W&&s>=W) a=1; s-=w[n];
for(i=n-1,v=w[n];i;v=w[i--]){
s-=w[i];j=W-s;
for(k=W;k>=v;--k) Add(dp[k],dp[k-v]);
for(k=max(0,j-w[i]+1);k<=j;++k) Add(a,dp[k]);
}
printf("%d\n",a);
return 0;
}

2. 在排列中插入(順列は挿入 DP)

在对排列计数的过程中,如果暴力统计当前还有多少个数没有插入,则需要状压 \(O(2^n)\) 种可能的情况。如果每个排列对应的贡献只和相邻元素的大小关系有关,则此时可以考虑 DP 升序/降序枚举每个元素插入的位置,保证已知相邻元素的大小关系。

例题2

题意

有 \(n\) 栋楼房,高度从 \(1\) 到 \(n\) 不等。求所有楼房有多少种可能的高度,使得从左端能看到 \(L\) 栋楼房,从右端能看到 \(R\) 栋楼房。\(n\le 300\)。

解法

考虑将所有楼房按照高度从大到小依次加入。此时每次新加入的楼房只有在序列的开头或结尾时才能造成贡献,而在插入中间时没有贡献。设 \(dp_{i,j,k}\) 为加入了高度为 \(1\sim i\) 的楼房,从左端能看到 \(j\) 栋,从右端能看到 \(k\) 栋的方案数。

例题3:CWOI 19th November 2022 T4

3. 按照区间起/终点大小选择区间(区間は終点でソート)

可以用于解决使用区间覆盖某些位置的问题。

例题4

题意

有 \(n\) 个在 \([0,X]\) 内的区间。求有多少种选择区间的方式使得选择的区间的并为 \([0,X]\)。\(n\le 10^5\)。

解法

(原文内解法有误)将所有区间按照左端点升序排序后,选择的一些区间一定会覆盖 \([0,X]\) 的某个前缀。设 \(dp_{i,j}\) 为使用前 \(i\) 个区间覆盖 \([0,j]\) 的方案数,设第 \(i\) 个区间为 \([L_i,R_i]\),则转移即为 \(\forall j\ge L_i,dp_{i-1,j}\to dp_{i,\max(j,R_i)}\)。可以使用权值线段树优化计算。

三、改写条件(条件の言い換え)

某些时候题目所给出的条件比较复杂,此时需要提炼出一个足够严谨而简洁的充要条件代替之。

例题1:A or...or B Problem

题意

求 \([A,B]\) 中的若干数(至少一个)的按位或有多少种。\(A,B<2^{60}\)。

解法

考虑去掉二进制数 \(A,B\) 的 LCP,然后找出一个最大的 \(2^p\) 满足 \(A<2^p\le B\),然后讨论 \([A,2^p)\) 和 \([2^p,B]\) 的对应答案。

显然 \([A,2^p)\) 内取任意数的按位或一定小于 \(2^p\),所以这部分内对答案造成的贡献为 \(2^p-A\);而对于 \([2^p,B]\),考虑满足 \(2^p+2^q\le B<2^p+2^{q+1}\) 的最大 \(q\),此时 \(\forall v\in[2^p,2^p+2^q)\),将它们和 \(2^p+2^q\) 按位或可得 \([2^p+2^q,2^p+2^{q+1})\) 内的所有数;且 \([2^p,B]\) 内的所有数按位或均小于 \(2^p+2^{q+1}\),所以这部分对答案造成的贡献为 \(2^{q+1}-1\)。

然后考虑分别取 \([A,2^p)\) 和 \([2^p,B]\) 内的任意数按位或(就是取 \([A,2^p)\) 和 \([2^p,2^p+2^{q+1}-1]\) 中各一个数按位或)的数量。此时显然这个值的最小值为 \(2^p+A\),最大值为 \(2^{p+1}-1\),且 \(\forall v\in[A,2^p),v\,{\rm{AND}}\,2^p\) 可以取遍 \([2^p+A,2^{p+1}-1]\) 内的所有数。将所有答案区间取并即可得出答案。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
long long a,b,p,q;
int main(){
scanf("%lld%lld",&a,&b);
if(a==b){putchar('1');return 0;}
for(q=a^b,p=1;p<=q;p<<=1);
--p; a&=p; b&=p;
for(p=1;p<=b;p<<=1); p>>=1;
for(q=1;p+q<=b;q<<=1);
printf("%lld",p+p+q-a-max(a,q));
return 0;
}

例题2:Eternal Average

题意

有 \(n\) 个 \(0\) 和 \(m\) 个 \(1\)。每次会删去 \(k\) 个数,然后加入它们的平均数。求最后留下的数的可能的值的数量对 \(10^9+7\) 取模。\(n,m,k\le 2\times 10^3\)。

解法

设最后留下的数为 \(Z\)。考虑使用 \(k\) 进制写出 \(Z\),则 \(Z\) 的所有位上的数字和和 \(m\) 在模 \(k-1\) 意义下同余。证明考虑将所有加法不进行仅为操作时,所有位上的数字之和刚好为 \(m\)。同时考虑使用相同的方法操作,但是将 \(0\) 和 \(1\) 互换,最后得到的数为 \(1-Z\),且对应的所有位上的数字和和 \(n\) 在模 \(k-1\) 意义下同余。(由于 \((m+n-1)\bmod (k-1)=0\),所以后者一定会发生)

此时如果存在对应的 \(Z\),设 \(c_i\) 为 \(Z\) 的第 \(i\) 位,\(d_i\) 为 \(1-Z\) 的第 \(i\) 位;则可以每次选择一个非 \(0\) 的 \(c_i\) 减一,然后将 \(c_{i+1}\) 加上 \(k\),直到 \(\sum_i c_i=m\)。同时对 \(d\) 也进行这样的操作。然后考虑整个合并的过程可以看成建出一棵 \(k\) 叉树的过程。然后考虑操作之前的 \(c_i\) 和 \(d_i\),设 \(l(c)\) 为满足 \(c_i\ne 0\) 的最大 \(i\),则 \(c_{l(c)}+d_{l(c)}=k\),且 \(\forall i<l(c),c_i+d_i=k-1\),可以构造出一棵合法的二叉树,其中每个 \(c_i+d_i\) 对应了深度为 \(i\) 的所有叶节点(可能为 \(0/1\))。然后在将某个 \(c_i\) 减一,将 \(c_{i+1}\) 加 \(k\) 的过程可以看成将一个叶节点变成一棵直径为 \(2\) 的 \(k\) 叉树的过程;所以操作后的 \(c,d\) 也可以建出对应的 \(k\) 叉树,每一种 \(c\) 均为合法。

注意 \(c\) 需要最后一位非 \(0\),需要特判。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=2010;
const int md=1000000007;
int n,m,k,i,j,a,b,s[maxn],dp[2][maxn][2];
inline void Add(int &x,int y){x-=((x+=y)>=md)*md;}
int main(){
scanf("%d%d%d",&n,&m,&k);
dp[0][0][0]=1;
b=max(n,m)<<1;
auto X=dp[0],Y=dp[1];
for(i=1;i<=b;++i){
Add(s[0]=X[0][0],X[0][1]);
for(j=1;j<=m;++j){
Add(s[j]=X[j][0],X[j][1]);
Add(s[j],s[j-1]);
}
for(j=0;j<=m;++j){
Add(Y[j][0]=X[j][0],X[j][1]);
Y[j][1]=s[j-1]; if(j>=k) Add(Y[j][1],md-s[j-k]);
if(!((m-j)%(k-1))&&i*(k-1)-j+1>=0&&i*(k-1)-j+1<=n) Add(a,Y[j][1]);
}
swap(X,Y);
}
printf("%d",a);
return 0;
}

四、结合贪心思想(greedy からの帰着)

例题1

题意

求有多少个 \(1\sim n\) 的排列可以被分成两个单增的子序列。\(n\le 2000\)。

解法

枚举某种划分方案对应的序列并不划算,因为某个序列可以有多种划分方案。考虑对于某个排列 \(p\) 如何判断其是否满足条件。设 \(dp_i\) 为考虑了前 \(i\) 个数,且 \(\max_{j=1}^i p_j\) 不在的另一个序列的末尾最小值为多少。如果新的 \(p_{i+1}>\max_{j=1}^i p_j\),则 \(dp_{i+1}=dp_i\),否则需要 \(p_{i+1}>dp_i\),\(dp_{i+1}=p_{i+1}\)。

考虑构造排列时,在排列中通过依次插入 \(1\sim n\) 的数来计算排列数量(避免算重,且确定大小关系可以更好转移)。显然每次插入后某个子序列的末尾一定是当前最后一个数。在插入完前 \(i\) 个数后,需要维护在这个序列内 另一个子序列的末尾的最小值(以免在使用其他划分方法时算重)的位置(维护后面的元素的插入方法)。设 \(dp_{i,j}\) 为插入前 \(i\) 个数,且另一个子序列末尾的最小值离末尾有 \(j\) 个元素时的方案数,转移时看 \(i+1\) 是否插入在末尾,有 \(dp_{i+1,j}=\sum_{k=j-1}^{i-1}dp_{i,k}\),可以使用后缀和优化计算。


所以在统计满足某种限制对应的序列数量时,由于贪心对应的策略会保证某个序列不会有多种贪心操作的方案,所以可以把目前贪心决策对应的状态作为 dp 状态,可以保证不重复。

例题2:Salaj

题意

有 \(n\) 个点。现在需要进行 \(n(n-1)\) 次操作,每次操作选择两个点 \(u,v\) 满足 \(u\to v\) 边不存在,然后连上 \(u\to v\) 的有向边。设 \(c_i\) 为第 \(i\) 次操作后图上的强连通分量个数,求有多少种 \(c\)。\(n\le 50\)。

解法(暂缺,不会证明)

知道如何证明者可以在下面补充证明。

补一下 \({\color{black}{\rm Z}}{\color{red}{\rm{MJ}}}\) 巨佬 的证明:

代码(暂缺)

点此查看代码

五、根据事件找准参数(場合分けのテクニック)

在对某些元素计数的时候,为了去重,如果不能使用容斥原理在计算完后去重,则应该找到一个能够和元素一一确定的一个量。

例题1

题意

有一个长为 \(n\) 的数组 \(a\)。现在需要选出若干数分别分到 \(A,B\) 集合,满足 \(\forall i\in A,j\in B;i<j\);求有多少种分的方法满足 \(\sum_{i\in A}i=\sum_{j\in B}j\)。\(n,|a|\le 100,a\) 中的数互不相同。

解法

排序后的 \(a\) 中,\(A\) 和 \(B\) 一定会在两个不交的前后缀内。如果单独在前后缀内分别选择就会出现重复。考虑去重问题:设 \(A_{i,j}\) 为 强制选择了 \(\boldsymbol{a_i}\),且选择的所有数之和为 \(j\) 的方案数。转移时可以使用普通背包。然后在每个后缀同样进行一次背包即可。

例题2:Piling Up

题意

一开始有 \(n\) 个颜色为黑白的球,但不知道黑白色分别有多少, \(m\) 次操作,每次先拿出一个球,再放入黑白球各一个,再拿出一个球,最后拿出的球按顺序排列会形成一个颜色序列,求颜色序列有多少种。答案对 \(10^9+7\) 取模。\(n,m\le 3\times 10^3\)。

解法

设 \(dp_{i,j}\) 为 \(i\) 次操作后,剩余 \(j\) 个白球的对应序列数。然而这样做会算重,例如序列 白 白 会同时在 \(dp_{1,0}\sim dp_{1,m-1}\) 里面出现。

然后考虑只让某个序列在一个 dp 值内出现,但是同时需要维护每个 dp 值对应的转移。考虑实际上某个序列对应了原有的白球需要在某个区间里面,且这个区间一定会随着序列的长度而减小。此时可以直接取区间左端点对应的 dp 值计入答案。转移时设 \(dp_{i,j,0/1}\) 表示 \(i\) 次操作,剩余 \(j\) 个白球,且白球是否被取完的序列数,最后取 \(\sum_{i=0}^mdp_{n,i,1}\) 为答案即可。

代码

点此查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=3010;
const int md=1000000007;
int n,m,i,j,w,b,dp[2][maxn][2];
inline void Add(int &x,int y){x-=((x+=y)>=md)*md;}
int main(){
scanf("%d%d",&n,&m);
auto X=dp[0],Y=dp[1]; X[0][1]=1;
for(i=1;i<=n;++i) X[i][0]=1;
for(i=1;i<=m;++i){
for(j=0;j<=n;++j){
if(j){
b=(j==1); w=X[j][0];
Add(Y[j-1][b],w);
Add(Y[j][b],w);
w=X[j][1];
Add(Y[j-1][1],w);
Add(Y[j][1],w);
}
if(j!=n){
w=X[j][0];
Add(Y[j][0],w);
Add(Y[j+1][0],w);
w=X[j][1];
Add(Y[j][1],w);
Add(Y[j+1][1],w);
}
}
swap(X,Y); memset(Y,0,(m+1)<<3);
}
for(i=w=0;i<=m;++i) Add(w,X[i][1]);
printf("%d",w);
return 0;
}

计数 dp 部分例题(一~五部分)的更多相关文章

  1. [DP之计数DP]

    其实说实在 我在写这篇博客的时候 才刚刚草了一道这样类型的题 之前几乎没有接触过 接触过也是平时比赛的 没有系统的做过 可以说0基础 我所理解的计数dp就是想办法去达到它要的目的 而且一定要非常劲非常 ...

  2. HDU5800 To My Girlfriend 背包计数dp

    分析:首先定义状态dp[i][j][s1][s2]代表前i个物品中,选若干个物品,总价值为j 其中s1个物品时必选,s2物品必不选的方案数 那么转移的时候可以考虑,第i个物品是可选可可不选的 dp[i ...

  3. CodeForces 176B Word Cut (计数DP)

    Word Cut Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit St ...

  4. HDU4815/计数DP

    题目链接[http://acm.hdu.edu.cn/showproblem.php?pid=4815] 简单说一下题意: 有n道题,每到题答对得分为a[ i ],假如A不输给B的最小概率是P,那么A ...

  5. HDU 6377 度度熊看球赛 (计数DP)

    度度熊看球赛 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Subm ...

  6. 计数dp

    计数dp 计数类的$dp$没做过几个,所以之前都放到"思维"标签下了,后来发现原来这属于一类问题啊...搬过来了. 管道取珠:https://www.lydsy.com/Judge ...

  7. [SDOI2010]地精部落[计数dp]

    题意 求有多少长度为 \(n\) 的排列满足 \(a_1< a_2> a_3 < a_4 \cdots\) 或者 $a_1> a_2 < a_3 > a_4\cdo ...

  8. 【BZOJ】2111: [ZJOI2010]Perm 排列计数 计数DP+排列组合+lucas

    [题目]BZOJ 2111 [题意]求有多少1~n的排列,满足\(A_i>A_{\frac{i}{2}}\),输出对p取模的结果.\(n \leq 10^6,p \leq 10^9\),p是素数 ...

  9. 【AtCoder】AGC022 F - Leftmost Ball 计数DP

    [题目]F - Leftmost Ball [题意]给定n种颜色的球各k个,每次以任意顺序排列所有球并将每种颜色最左端的球染成颜色0,求有多少种不同的颜色排列.n,k<=2000. [算法]计数 ...

  10. 【BZOJ】4559: [JLoi2016]成绩比较 计数DP+排列组合+拉格朗日插值

    [题意]n位同学(其中一位是B神),m门必修课,每门必修课的分数是[1,Ui].B神碾压了k位同学(所有课分数<=B神),且第x门课有rx-1位同学的分数高于B神,求满足条件的分数情况数.当有一 ...

随机推荐

  1. 数值分析之解线性方程组的直接方法 5.X

    矩阵 谱分解 设 \(\boldsymbol{A}=a_{i j} \in \mathbb{R}^{n \times n}\) , 若存在数 \(\lambda\) (实数或复数) 和非零向量 \(\ ...

  2. LinuxK8S集群搭建三(部署dashboard)

    系统环境: CentOS 7 64位 准备工作: 通过虚拟机创建三台CentOS服务器,可参照之前的文章192.168.28.128 --master192.168.28.130 --node0119 ...

  3. element ui中table动态列切换时,表格样式变形

    现象:定义多个头部和多个数据体,可以自由切换不同的头部和相应的数据体,但是切换过程表格会变形. 解决办法:table增加索引,切换头部和数据时,修改为不同的索引,即可解决 重点:表格标签上的  key ...

  4. Datax-web的入门使用

    在学习入门之前,需要先启动Datax-web(Datax-web入门配置与启动) 1.登录 账户:admin 密码:123456 2.创建项目 3.新建执行器 项目中有默认的,可以直接使用 4.新建数 ...

  5. 别再写一堆的 for 循环了!Java 8 中的 Stream 轻松遍历树形结构,是真的牛逼

    实体类:Menu.java /** * Menu * * @author lcry */ @Data @Builder public class Menu { /** * id */ public I ...

  6. 电商项目maven框架搭建引入dubbo配置文件报错

    解决:dubbo配置文件报红叉的问题 构建dobbo-provider配置文件时,报红叉错误,本质即找不到对应的dubbo.xsd文件. 1.下载模板 模板下载地址:http://download.c ...

  7. ssr 学习总结

    自己构建ssr 前提:了解  koa, koa-router, koa-static, webpack 文件结构 ssr  中的router store 都是  一个工厂函数 在服务器端渲染(SSR) ...

  8. Mysql-不同场景下操作/查询数据库表

    1. 通过关联字段把一张表的字段值更新另一张表的字段值 update table_a a, table_b b set a.username = b.username where a.id = b.i ...

  9. Flink任务自定义个性化配置logback.xml文件

    之前已经写过如何使用logback将日志直接写入Kafka,然后通过es和kibana实时查看 但是如果我们想要每个任务都能够带上单独的信息比如开发者.任务名称等信息,那么就需要每个任务都指定一个lo ...

  10. GET请求数据量大造成的问题

    在实际的开发过程中,我们偶尔或者遇到过要导出列表中所有的数据.假设列表中有十万条数据,那么导出所有,意味着要大批量的走查询接口,通常我们的后台的API接口GET请求支持的查询长度不得大于1000,(比 ...