COCI2015/2016 Contest#6 D 游戏
COCI2015/2016 Contest#6 D 游戏
题目描述:
Mirko 和 Slavko 在玩一个游戏,先由Mirko在1~N中选出几组互质的数,例如 \(N=5\) 时,Mirko 可以选的组有 \({(1,2),(1,3),(1,4),(1,5),(2,3)\dots}\)。
然后轮到 Slavko,Slavko 的任务就是找到一个整数 \(x(2≤x≤N)\),使得对于每一组数 \((a,b)\) 都满足以下两个条件之一
• \(a, b < x\)
• \(a, b \ge x\)
例如,如果 Mirko 选了 \({(1,2),(3,4)}\),那么x可以=3;
如果 Slavko 找不到满足条件的 \(x\) 值,则表示 Mirko 获得胜利,现在请你告诉 Mirko ,他有多少种情况可以赢。
首先,我们预处理出所有互质对,显然,互质对的个数最多只有 \(\dfrac{n\times(n-1)}{2}\) 个。我们将互质对 \((i,j)\) 抽象成一条左端点在 \(i\),右端点在 \(j\) 的线段 ,那么我们要求的就是这么多条线段,任选其中的几条构成一条连续的,左端点在 1,右端点在 \(n\) 的线段。考虑使用 dp 解决这个问题。
我们设 \(dp_{i,j}\) 表示前 \(i\) 条线段,构成有效连续部分为 1到 \(j\) 的线段的方案数。容易得到转移式
其中,\(L_i,R_i\) 分别表示第 \(i\) 条线段的左右端点。注意到,这个转移式如果正确,那么所有 \(R\) 比 \(R_i\)
的点都必须在 \(i\) 转移之前转移,所以我们得将所有线段按右端点排序。但是只有这个式子是不对的,对于有效连续部分的右段在 \([1,L_i-1]\) 区间内的这些线段的方案数也要转移,而且转移后的有效连续部分的右端不变。相当于 \(i\) 这条线段对这种方案没有任何贡献。但它们的方案是不同的,因为 \(i\) 被选了。所以还有一条式子:
接下来按照这些式子转移就行了。
转移部分的代码如下:
for(int i=1;i<=cnt;++i)
{
for(int j=1;j<a[i].l;++j)
dp[i][j]=dp[i-1][j];
for(int j=a[i].l;j<=n;++j)
dp[i][a[i].r]=(dp[i-1][j]+dp[i][a[i].r])%MOD;
for(int j=1;j<=n;++j)
dp[i][j]=(dp[i-1][j]+dp[i][j])%MOD;
}
全部代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MOD = 1e9;
int n;
int gcd(int x,int y)
{
if(y==0) return x;
return gcd(y,x%y);
}
struct line
{
int l,r;
bool operator < (const line &x)const
{
return r<x.r;
}
}a[405];
ll dp[405][25];
int main()
{
scanf("%d",&n);
int cnt=0;
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
if(gcd(i,j)==1) a[++cnt]=line{i,j};
sort(a+1,a+1+cnt);
dp[0][1]=1;
for(int i=1;i<=cnt;++i)
{
for(int j=1;j<a[i].l;++j)
dp[i][j]=dp[i-1][j];
for(int j=a[i].l;j<=a[i].r;++j)
dp[i][a[i].r]=(dp[i-1][j]+dp[i][a[i].r])%MOD;
for(int j=1;j<=n;++j)
dp[i][j]=(dp[i-1][j]+dp[i][j])%MOD;
}
printf("%lld",dp[cnt][n]%MOD);
return 0;
}
总结:dp的阶段划分一定要清楚明白,如这题划分成不选,选了有贡献,选了无贡献。如果不划分清楚明白的话很可能会把选了无贡献这部分忘记转移使答案错误。
原文地址:https://www.cnblogs.com/nightsky05/p/15109073.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python正则表达式快速学习
- 如何上传项目到GitHub
- MySQL查询优化-基于EXPLAIN
- Python操作SQLite数据库
- Python多进程及多线程基础
- Python字符串三种格式化输出
- 你需要知道的Python代码规范性检查(pylint和flake8)
- Linux下安装python环境
- 【5】进大厂必须掌握的面试题-Java面试-spring
- Python 3.7 自动化接口测试简单实例
- 从 0 开始构建一个亿级请求的微服务架构
- ruby+cucumber+watir环境搭建
- Python常用模块os和shutil学习
- Python简单实现批量下载无版权图片
- Pycharm自动添加文件头注释和函数注释参数