其实说实在 我在写这篇博客的时候 才刚刚草了一道这样类型的题 之前几乎没有接触过 接触过也是平时比赛的 没有系统的做过 可以说0基础

我所理解的计数dp就是想办法去达到它要的目的 而且一定要非常劲非常快 都是一个很小的数然后有很多种接下来的方案使得这个数一下子变很大

计数DP常用的有:组合和排列 然后要抽象的想 还有容斥定理(这的话经常考而且很难几乎不会做) 还有用前缀之类的进行优化转移 找到规律就可以搞了

慢慢给出例题慢慢说慢慢学 因为这个要不全AC要不全WA

[JLOI2013]地形生成

计数dp的第一题 看了题意一下子懵比 感受到了计数dp的厉害性 表示连暴力都不会打

然后看题解 自己推了做了死吭了一天 (妈的旁边合唱室的脑瓜有病啊我去 叫了一整天还不给我唱征服..)

首先我们发现 如果小的插在大的前面是完全没有影响的 所以我们按两个关键字从大到小排 这样的话以后插入都没有影响

看上去好像第一问简单一点 就是求合法的标号序列 也就是合法的序列有多少个 那么想一想嘛 对于同一个高度的 你找到前面的你能插到哪里 再加上高度相同的而且在前面的

为什么要加上前面的呢 你想想 前面是不是也是找前面的 那么他们找了的话其实我当前的可以把这个位置忽略掉 并且前面的还会把它找的前面给挤出去 然后还多了个位置

比如说 x y 都在我承受的范围内 就有三个可以放的地方但是加上了前面高度相同的还有一个p 也就是变成了 x p y 那么是不是多了个位置啊 就有四个地方可以插入了

然后就是高度序列的问题 高度序列其实想一想就是同一个高度的 然后两两的位置不能变 这也和我们两个关键字排序有关 小的在前大的在后 这样的话保证高度相同时后面的可以放在前面去

不能交换的话 那么怎么做呢 其实也很简单 想想就好

设F[i][j]表示现在是第i座山放在第j个位置上 占时对于这个高度有多少种方法

那么这个高度第一座山所有这座山能放位置的F[i][j]=1

考虑下一座山 不能放在上一座山的前面 不然就相当于这一座山是第一座 上一座是第二座 就交换了

所以的话F[i+1][j]=sigma(F[i][1..j-1]) 就是上一座山放在我前面的都可以继承下来 然后的话搞一个前缀和优化一下

F[i+1][j]=F[i+1][j-1]+F[i][j-1] 也就是说前面能选的我也可以选 前面不可以选的我可以选就是前面那座山在前面的位置

然后每个最后的山的状态的和加起来就好了 这就代表了这个高度的山一起放的方案数 然后乘一下就好

代码贼短不用怕

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define Maxn 1010
using namespace std;
const int Mod=;
pair<int,int>pr[Maxn];
bool Cmp(const pair<int,int> &x,const pair<int,int> &y){if(x.first!=y.first) return x.first>y.first; else return x.second<y.second;}
int F[Maxn][Maxn];
int main()
{
int N; scanf("%d",&N);
for(int i=;i<=N;i++) scanf("%d%d",&pr[i].first,&pr[i].second);
sort(pr+,pr+N+,Cmp); int ans1=,ans2=; memset(F,,sizeof(F)); for(int i=;i<=N;)
{
int now=i; while(now<N&&pr[now].first==pr[now+].first) now++;
for(int j=i;j<=now;j++)
{
ans1=(ans1*(min(pr[j].second,i)+j-i))%Mod; if(j==i){F[j][]=; for(int k=;k<min(pr[j].second,i)+j-i;k++) F[j][k]=(F[j][k-]+F[j][k])%Mod;}
else for(int k=;k<min(pr[j].second,i)+j-i;k++) F[j][k]=(F[j][k-]+F[j-][k-])%Mod;
}
int sum=; for(int j=;j<min(pr[now].second,i)+now-i;j++) sum+=F[now][j];
ans2=(ans2*sum)%Mod; i=now+;
}
return printf("%d %d",ans1,ans2),;
}
/*
2
1 2
2 2
*/

Codeforce 382.E Ksenia and Combinatorics

好难啊啊啊 好想死啊 做了我一天半

题目有一个最大匹配数 有一个不同子树形态 数学老师其实教过我们做题要有化归思想

单单求子树形态我们可以有两种方法:

1.强制左树小于右树且左树和右树相同时 最小的数在左树

2.强制左树小于右树且相同时 /2

单单求最大匹配数我们可以有  F[i][0/1]表示与不与根匹配 转移显然

然后要合起来 怎么办呢 定义F[N][K][0/1]表示N个点最大匹配数为k然后最上面的点选不选

然后我们固定一个根

复制一下别人的图 其实C(k,i-1)就是选一边的 根节点固定不能变 然后因为上一个状态继承下一个状态的时候 下一个状态的根节点是可以变得 所以要两边分别乘k和(i-k-1)

然后没了 好多细节有点难打 注意相同节点个数的时候要除2(画图大概意会了一下想了好久不会证,大概是所有形态只是选的方式不同 形态是一样的) k=0是要*1

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
typedef long long LL;
const LL Mod=1e9+;
LL N,K; LL C[][]; LL F[][][];
void Pre()
{
C[][]=; for(LL i=;i<=N;i++) C[i][]=;
for(LL i=;i<=N;i++) for(LL j=;j<=i;j++) C[i][j]=(C[i-][j-]+C[i-][j]);
}
int main()
{
scanf("%I64d%I64d",&N,&K); Pre();
F[][][]=; F[][][]=;
for(LL p=;p<=N;p++)
{
for(LL q=;q<=p/;q++)
{
for(LL i=;i<=(p-)/;i++)
{
for(LL j=;j<=i/;j++)
{
LL k0=,k1=; if(i==p-i-) k0++; if(i==p-i-) k1++;
LL A=i; LL B=p-i-; if(A==) A++; LL cz=((C[p-][i]/k0)*A*B)%Mod;
cz=(cz*F[i][j][])%Mod; cz=(cz*F[p-i-][q-j][])%Mod;
F[p][q][]=(F[p][q][]+cz)%Mod; cz=((C[p-][i]/k1)*A*B)%Mod;
cz=(cz*((F[i][j][]*F[p-i-][q-j-][])%Mod+(F[i][j][]*F[p-i-][q-j-][])%Mod+(F[i][j][]*F[p-i-][q-j-][])%Mod))%Mod;
F[p][q][]=(F[p][q][]+cz)%Mod;
}
}
}
}
printf("%I64d\n",(F[N][K][]+F[N][K][])%Mod);
return ;
}
hdu5713 K个联通块

绝世好题啊(不是bzoj4300..)

首先N这么小 就应该想到什么组合容斥状压 然后又有一个K 很明显这是要转移的

F[sta][K]表示点的状态为sta 分成K份的方案数 那么我们考虑转移 先在状态中抽出一个点 然后和其余的点互相成为联通块

比如说这个状态有4个点 1 2 3 4 我把1抽出来 使得1 12 13 14 123 124 134成为联通块设为上一个状态s1 然后求解 F[sta][K]=Sigma(F[s1][1],F[sta^s1][k-1])

这样就没有遗漏的 这是liao教我的 因为这样保证了你1这个联通块是不同的 然后其他的块随便取 这样就保证结果都是不同的 而且1是一定要取得,全部都会取完

也就是1总得要属于一个联通块 然后你把联通块枚举出来 其它一定不同 而且一定要算了

但是我们需要做的是F[sta][1] 其实的话这个状态就可以转换成G[sta]-H[sta] G是这个状态所有的边的方案数 通过2^(边数)可以求出 然后H就是这个状态不联通的个数

H的求法类似于F H[sta]=H[s1]*G[sta^s1] 就是随便抽一个点出来 然后其它怎么连都不关我事 这样就每个和这个点的联通块都过了一变 保证不重复

求子集有点妙 自己看看代码意会

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define Maxn 15
using namespace std;
typedef long long LL;
const int Mod=1e9+;
struct node{int x,y,next;}edge[Maxn*Maxn*]; int len,first[Maxn];
void ins(int x,int y){len++; edge[len].x=x; edge[len].y=y; edge[len].next=first[x]; first[x]=len;}
int T,K,N,M; inline int low_bit(int x){return x&(-x);} LL G[<<Maxn]; LL F[Maxn][<<Maxn]; LL H[<<Maxn];
LL bit[Maxn*Maxn];
int main()
{
scanf("%d",&T);
for(int Tcase=;Tcase<=T;Tcase++)
{
scanf("%d%d%d",&N,&M,&K); len=; memset(first,-,sizeof(first));
for(int i=;i<=M;i++){int a,b; scanf("%d%d",&a,&b); if(a>=b) ins(a,b); else ins(b,a);}
bit[]=; for(int i=;i<=M;i++) bit[i]=(bit[i-]<<)%Mod;
memset(F,,sizeof(F)); memset(G,,sizeof(G)); memset(H,,sizeof(H)); for(int i=;i<(<<N);i++)
{
int sum=;
for(int x=;x<=N;x++)
for(int k=first[x];k!=-;k=edge[k].next)
{
int y=edge[k].y;
if((i&(<<(x-)))&&(i&(<<(y-))))
sum++;
}
G[i]=bit[sum];
} for(int i=;i<(<<N);i++)
{
int last=i-low_bit(i);
for(int j=last;j;j=(j-)&last)
H[i]=(H[i]+(F[][i-j]*G[j]))%Mod;
F[][i]=(G[i]-H[i]+Mod)%Mod;
} for(int k=;k<=K;k++)
for(int i=;i<(<<N);i++)
{
int last=i-low_bit(i);
for(int j=last;j;j=(j-)&last)
F[k][i]=(F[k][i]+(F[][i-j]*F[k-][j]))%Mod;
} printf("Case #%d:\n",Tcase);
int ans=; printf("%lld\n",F[K][(<<N)-]);
}
return ;
}

[DP之计数DP]的更多相关文章

  1. POJ 1037 (计数 + DP) 一个美妙的栅栏

    这道题总算勉勉强强看懂了,DP和计数都很不好想 DP部分: 称i根木棒的合法方案集合为S(i),第二根木棒比第一根长的方案称作UP方案,反之叫做DOWN方案 C[i][k][DOWN] 是S(i)中以 ...

  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. BZOJ 1833: [ZJOI2010]count 数字计数( dp )

    dp(i, j, k)表示共i位, 最高位是j, 数字k出现次数. 预处理出来. 差分答案, 对于0~x的答案, 从低位到高位进行讨论 -------------------------------- ...

  5. HDU4815/计数DP

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

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

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

  7. 计数dp

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

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

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

  9. 【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是素数 ...

随机推荐

  1. 浅谈JavaScript中的call和apply

    语法 fun.apply(thisArg, [argsArray]) fun.call(thisArg, arg1, arg2, ...) apply 接收两个参数,第一个参数指定了函数体内this对 ...

  2. 通过DialogFragment从DatePicker或TimePicker中获取日期数据

    通过DialogFragment从DatePicker或TimePicker中获取日期数据 一个activity类,里面存有date和time的变量,想通过dialogfragment的方式获取用户输 ...

  3. wp加载本地HTML(附带图片,CSS,JS)

    wp加载本地HTML(附带图片,CSS,JS) Windows Phone:Load Local HTML with Img,Css,Js by 唐小崇 http://www.cnblogs.com/ ...

  4. Servlet部署描述文件(web.xml)

    最近看了下配置文件(Deployment Descriptor:简称DD),又称部署描述文件,下面详细介绍下该文件的组成和作用: 一.<web-app>有四个属性: 1.xmlns:申明了 ...

  5. building android/ubuntu-touch on 32bit machine

    host C: libhost <= build/libs/host/CopyFile.c host StaticLib: libhost (/media/linux/1/touch/expor ...

  6. 一口一口吃掉Hexo(一)

    如果你想得到更好的阅读效果,请访问我的个人网站 ,版权所有,未经许可不得转载! 这里是我的个人博客网站,点击这里你可以到我的首页瞧瞧.我之前使用的是第三方的博客平台--博客园,点击这里可以看到我的博客 ...

  7. 聊聊数据库(MySql)连接吧,你真的清楚吗?

    前言 说到数据库连接,这个大家都很熟悉了.但是熟悉一般来自于下面三种情况 * 刚开始学编程的时候,老师就说用完的数据库连接一定要关闭,不然会有严重的后果. * 编程一段时间后,大家都说要用连接池来优化 ...

  8. 基于AFNetworking 3.0的取消已发出的网络请求

    一般情况下主动取消请求的需求不会太多 除非以下几种情况 1.比如电商应用为例 请求频繁,数据量大 2.对性能的要求比较高 3.网络环境比较差 当一个用户打开一个界面 看到的却是漫长的等待框 这时候用户 ...

  9. 《如何阅读一本书》(How to Read a Book)

    值得一读的书,有深入浅出,也有并不能完全读懂的部分,以下是第11章对之前内容的总结整理. 阅读的层次 1. 基础阅读 2. 检视阅读 3. 分析阅读 4. 主题阅读 分析阅读 第一阶段:这本书在谈些什 ...

  10. python_login输入三次错误密码锁定密码_密码不允许为空

    #!/usr/bin/env python #_*_coding:utf-8_*_ #by anthor zhangxiaoyu 2017-01-10 import getpass import os ...