【BZOJ3215/3216】[ZJOI2013]话旧/话旧2(组合数学,动态规划)

题面

BZOJ3215

BZOJ3216

题解

先解决\(3216\),求的是最小值为\(0\)。

因为起点就是\(0\),所以就是在过程中不会到\(0\)以下。

那么两个相邻位置的合法走法可以转化成网格图上从\((0,0)\)走到\((n,m)\),且不穿过直线\(y=x-b\)的方案数。

这个方案数显然可以组合数计算\(\displaystyle {n+m\choose n}-{n+m\choose n+b}\)。因为模数很蛋疼,所以\(exLucas\)一下就好了。其实也没有必要\(exLucas\),因为模数分解后就是两个质数的乘积,所以直接\(Lucas\)后\(CRT\)合并就好了。

代码放最后面。


然后来解决\(3215\),求的是极小值为\(0\)。

在路径上翻译一下的话就是只要往下走就必定走到\(0\)位置。

因为需要访问到当前点的时候,路径是在往下还是往上,所以来\(dp\),设\(f[i][0/1]\)表示当前在\(i\)位置,是路径是在往上还是往下,分情况考虑转移。

  • \(f[i][1]\rightarrow f[i+1][0]\)

先考虑最简单的一种情况,即当前点的路径还在往下,而要用一条往上的路径穿过\(i+1\)。那么延长这两条路径,能够确定两个\(0\)点,剩下的就是在这两个零点之间反复横跳,设这两个零点之间的距离为\(2k\),那么要进行\(k\)次向上\(k\)次向下,而分组后两者的分组必定两两相等,所以就是把\(k\)分成任意数量组的方案数,这个答案是\(2^{k-1}\)。即对于\(i\)考虑,其要么和\(i-1\)在一组要么不在。

  • \(f[i][0]\rightarrow f[i+1][0]\)

    强行把\(i\)当做当前\(i\)节点的往上的路径的终点,那么又能确定两个\(0\)点,还是假设中间有\(2k\)个位置,这时候的答案是\(2^k\)。首先还是可以任意分组,但是第一次还可以选择是否从\(i\)继续向上延伸。

  • \(f[i][1]\rightarrow f[i][1]\)

    首先左侧一定要走到底,那么还是可以确定两个\(0\)点。依旧分组,方案数是\(2^{k-1}\),因为右侧需要从上面下来,所以强行把最后一段和右侧合并。

  • \(f[i][0]\rightarrow f[i+1][1]\)

    还是强制先到\(0\),还是中间是\(2k\)个位置,此时的贡献就是\(2^{k}\)。因为对于左侧考虑是否把第一段给合并进来,右侧强制把最后一段给合并进来,所以要考虑\(k\)个东西。

那么直接\(dp\)就完了,最大值随便求求就好了。

注意这里有些特殊情况,导致\(k\le 0\),把这些情况特判处理就好了。


BZOJ3215代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 19940417
#define MAX 1000100
void add(int &x,int y){x=(x+y)%MOD;}
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int fpow(int a,int b)
{
int s=1;
while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return s;
}
struct Data{int x,y;}a[MAX];
bool operator<(Data a,Data b){return a.x<b.x;}
bool operator==(Data a,Data b){return a.x==b.x&&a.y==b.y;}
int n,K,mx;
int f[MAX][2];
int main()
{
n=read();K=read();
for(int i=1;i<=K;++i)a[i].x=read(),a[i].y=read();
a[++K]=(Data){0,0};a[++K]=(Data){n,0};
sort(&a[1],&a[K+1]);K=unique(&a[1],&a[K+1])-a-1;
f[1][1]=1;
for(int i=1;i<K;++i)
{
int p=a[i+1].x-a[i].x-a[i+1].y-a[i].y;p>>=1;
mx=max(mx,(a[i+1].x+a[i+1].y-a[i].x+a[i].y)/2);
if(a[i+1].y-a[i].y==a[i].x-a[i+1].x)add(f[i+1][1],(f[i][0]+f[i][1])%MOD);
else if(a[i+1].y-a[i].y==a[i+1].x-a[i].x)add(f[i+1][0],(f[i][0]+(a[i].y?0:f[i][1]))%MOD);
else if(p<0)add(f[i+1][1],f[i][0]);
else if(p==0)add(f[i+1][0],(f[i][0]+f[i][1])%MOD),add(f[i+1][1],f[i][0]);
else
{
int d=fpow(2,p-1);
if(a[i+1].y)add(f[i+1][0],(f[i][1]+2ll*f[i][0])*d%MOD);
add(f[i+1][1],(f[i][1]+2ll*f[i][0])*d%MOD);
}
}
printf("%d %d",f[K][1],mx);
return 0;
}

BZOJ3216代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 19940417
#define MAX 1000100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Data{int x,y;}a[MAX];
bool operator<(Data a,Data b){return a.x<b.x;}
int fac[3]={0,7,2848631};
int jc[3][2848631];
int inv[3][2848631];
void exgcd(int a,int b,int &x,int &y){if(!b){x=1,y=0;return;}exgcd(b,a%b,y,x);y-=a/b*x;}
int Inv(int n,int m){int x,y;exgcd(n,m,x,y);return (x%m+m)%m;}
int C(int n,int m,int p)
{
if(n<m)return 0;
return 1ll*jc[p][n]*inv[p][m]%fac[p]*inv[p][n-m]%fac[p];
}
int Lucas(int n,int m,int p)
{
if(n<p)return C(n,m,p);
return 1ll*Lucas(n/fac[p],m/fac[p],p)*C(n%fac[p],m%fac[p],p)%fac[p];
}
int C(int n,int m)
{
int w[3]={0,0,0};if(n<m||n<0||m<0)return 0;
for(int i=1;i<=2;++i)w[i]=Lucas(n,m,i);
int x=Inv(fac[1],fac[2]);
x=1ll*x*(w[2]-w[1]+MOD)%MOD;
return (1ll*x*fac[1]+w[1])%MOD;
}
int Calc(int n,int m,int b)
{
int ret=C(n+m,n)-C(n+m,n+b);
return (ret+MOD)%MOD;
}
int n,K,ans=1,mx;
int main()
{
n=read();K=read();
for(int i=1;i<=K;++i)a[i].x=read(),a[i].y=read();
a[++K]=(Data){0,0};a[++K]=(Data){n,0};
sort(&a[1],&a[K+1]);
for(int i=1;i<=2;++i)
{
jc[i][0]=inv[i][0]=inv[i][1]=1;
for(int j=1;j<fac[i];++j)jc[i][j]=1ll*jc[i][j-1]*j%fac[i];
for(int j=2;j<fac[i];++j)inv[i][j]=1ll*inv[i][fac[i]%j]*(fac[i]-fac[i]/j)%fac[i];
for(int j=2;j<fac[i];++j)inv[i][j]=1ll*inv[i][j-1]*inv[i][j]%fac[i];
}
for(int i=1;i<K;++i)
{
int b=a[i].y+1;
int n=a[i+1].x-a[i].x;
if(!n)continue;
int m=a[i+1].y-a[i].y;
int up=(n+m)/2,dn=(n-m)/2;
ans=1ll*ans*Calc(up,dn,b)%MOD;
mx=max(mx,a[i].y+up);
}
printf("%d %d\n",ans,mx);
return 0;
}

【BZOJ3215/3216】[ZJOI2013]话旧/话旧2(组合数学,动态规划)的更多相关文章

  1. 天气预报API(二):全球城市、景点代码列表(“旧编码”)

    说明 2016-12-10 补充 (后来)偶然发现中国天气网已经有城市ID列表的网页...还发现城市编码有两种,暂且称中国天气网这些编码为旧标准"旧编码"的特征是 9个字符长度; ...

  2. 免费图片存储和图话【提供demo下载】

    我们不管是做博客系统还是其他网站,图片是免不了要使用到的.但是,我们都知道图片的访问是很耗资源的,同时也是很占磁盘空间的,且还特别占带宽. 所以,我们一般都会用到特定的图片服务器.不过,像我等屌丝平时 ...

  3. 天气预报API(一):全国城市代码列表(“旧编码”)

    说明 2016-12-09 补充 (后来)偶然发现中国天气网已经有城市ID列表的网页... 还发现城市编码有两种,暂且称中国天气网这些编码为旧标准 "旧编码"的特征是 9个字符长度 ...

  4. P 1029 旧键盘

    转跳点:

  5. Python之列表、字符串、元组和字典的基本用法

    1 模块初识 Python的强大之处在于他有非常丰富和强大的标准库和第三方库,几乎你想实现的任何功能都有相应的Python库支持,以后的课程中会深入讲解常用到的各种库,现在,我们先来象征性的学2个简单 ...

  6. <老友记>学习笔记

    这是六个人的故事,从不服输而又有强烈控制欲的monica,未经世事的千金大小姐rachel,正直又专情的ross,幽默风趣的chandle,古怪迷人的phoebe,花心天真的joey——六个好友之间的 ...

  7. 银行HR:寒门再难出贵子

    银行HR:寒门再难出贵子来源:金融行业网 2013 年 8 月 6 日 来源:天涯社区 作者:永乐大帝二世 本文是一位银行的HR写的,他工作了10年,接待了一群到银行实习的实习生,然后观察他们发生的好 ...

  8. linux + shell 命令等

    Linux命令[注意:建议用UltraEdit打开] 一.文件处理命令 1.命令格式与目录处理命令 ls –a[查看隐藏文件] ls –l[查看文件信息长格式显示] ls –d[查看指定目录的详细信息 ...

  9. Spring.net(二)----初探IOC容器

    我在上一篇关于Spring.net的文章“Spring.NET框架简介及模块说明 ”中很详细的介绍了,本文就不旧话从提.我门就直奔主题吧. 1.首先了解两个接口.  IObjectFactory接口和 ...

随机推荐

  1. Python之操作Excel

    使用之前先导入三个模块: import xlwt #只能写Excel import xlrd #只能读Excel import xlutils #修改Excel,在原来的基础上修改 一.写EXCEL ...

  2. 【问题解决方案】本地代码文件上传到GitHub里中文乱码问题

    刚刚学完Git并试着上传了我的化石Java代码到远程库,表面一切和谐,然而.. 真让人大惊失色.. step1-检查浏览器是否是utf-8(谷歌默认是) step2-在本地编辑器设置 (按理说,not ...

  3. 开发工具之Sublime编辑器

    sublime是一款轻量级的编辑器,可以从官网上进行下载最新版本.它有很多使用并且强大的功能支持.例如:GOTO,package 等快捷操作.但有时候下载的版本不能进行安装package contro ...

  4. opencv2\core\cuda.hpp(106): error C2059: 语法错误:“常量”

    在 cuda.hpp 中, virtual void free(GpuMat* mat) = 0;   -> virtual void _free(GpuMat* mat) = 0;

  5. Linux中各个目录作用

    对于linux新手来说,最感到迷惑的问题之一就是文件都存在哪里呢?特别是对于那些从windows转过来的新手来说,linux的目录结构看起来有些奇怪哦.比如没有C盘,没有分盘符,一大堆不知道用途的文件 ...

  6. Form组件归类

    一.Form类 创建Form类时,主要涉及到 [字段] 和 [插件],字段用于对用户请求数据的验证,插件用于自动生成HTML; 1.Django内置字段如下: 1 Field 2 required=T ...

  7. from组件补充

    一.定义的规则 class TeacherForm(Form): #必须继承Form # 创建字段,本质上是正则表达式 username = fields.CharField( required=Tr ...

  8. Java多线程系列——原子类的实现(CAS算法)

    1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...

  9. 设计模式笔记:开闭原则(OCP,The Open-Closed Principle)

    1. 开闭原则概述 开闭原则(OCP,The Open-Closed Principle)两个主要特征: (1)对扩展开放(open for extension):模块的行为的可以扩展的,当应用的需求 ...

  10. 莫烦scikit-learn学习自修第五天【训练模型的属性】

    1.代码实战 #!/usr/bin/env python #!_*_ coding:UTF-8 _*_ from sklearn import datasets from sklearn.linear ...