Chapter3数学与简单DP
Chapter 3 数学与简单DP
上取整:
a / b //下取整
(a + b - 1) / b //上取整
+++
数学
1.买不到的数目 1205
//如果不知道公式,可以暴搜打表找规律(★)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
bool dfs(int u, int n, int m)
{
if(!u) return true;
if(u >= n && dfs(u - n, n, m)) return true;
if(u >= m && dfs(u - m, n, m)) return true;
return false;
}
int main()
{
int n, m;
int res = 0;
cin >> n >> m;
for(int i = 0; i <= 1000; i++)
if(!dfs(i, n, m)) res = i;
cout << res << endl;
return 0;
}
/*打表
3 4 5
3 5 7
3 7 11
3 8 13
3 10 17
*/
AC code
#include <iostream>
using namespace std;
int main()
{
int n, m;
cin >> n >> m;
cout << (n - 1) * (m - 1) - 1 << endl;//公式,记住
return 0;
}
2.蚂蚁感冒 1211
//脑筋急转弯,,换位思考
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 55;
int ant[maxn];
int n;
int main()
{
cin >> n;
for(int i = 0; i < n; i++ ) cin >> ant[i];
int left = 0, right = 0;
for(int i = 1; i < n; i++ )
{
if(abs(ant[i]) < abs(ant[0]) && ant[i] > 0) left ++;
if(abs(ant[i]) > abs(ant[0]) && ant[i] < 0) right ++;
}
if(ant[0] > 0 && right == 0 || ant[0] < 0 && left == 0) cout << 1 << endl;
else cout << left + right + 1 << endl;
return 0;
}
3.饮料换购 1216
//小学数学题
#include <iostream>
using namespace std;
int sum, m;
void dfs(int u)
{
if(u < 3) return;
sum += u / 3;
dfs(u / 3 + u % 3);
}
int main()
{
cin >> m;
sum = m;
dfs(m);
cout << sum << endl;
}
- 简单DP
1.状态表示 : 数组元素 表示的是一个集合,存的当前集合的属性
i为行下标 j为列下标 表示只从前i个物品中选,物品总体积<= j
2.状态计算
集合的划分
1.01背包问题 2
//无优化版
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int f[maxn][maxn];//代表集合,存放符合需要的数据
int v[maxn], w[maxn];
int m, n;
int main()
{
cin >> m >> n;
for(int i = 1; i <= m; i++ ) cin >> v[i] >> w[i];
for(int i = 1; i <= m; i++ )
for(int j = 0; j <= n; j++ )
{
f[i][j] = f[i - 1][j];//不选第i个的情况
//选择第i个的情况
if(j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}
cout <<f[m][n] << endl;
return 0;
}
//优化版本
/*
1. f[i] 仅用到了f[i-1]层,
2. j与j-v[i] 均小于j
3.若用到上一层的状态时,从大到小枚举, 反之从小到大
*/
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int n, m;
int v[maxn], w[maxn];
int f[maxn];
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++ ) cin >> v[i] >> w[i];
for(int i = 1; i <+ m; i++ )
for(int j = m; j >= v[i]; j--)//j从大到小
f[j] = max(f[j], f[j - v[i]] + w[i]);
cout << f[m] << endl;
return 0;
}
2.摘花生 1015
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105;
int f[maxn][maxn], w[maxn][maxn];//f[][]为存放路线与路线最大值的二维数组
int m, n;
int T;
int main()
{
cin >> T;
while(T--)
{
scanf("%d%d", &m, &n);
for(int i = 1; i <= m; i++ )
for(int j = 1; j <= n; j++ )
scanf("%d", &w[i][j]);
for(int i = 1; i <= m; i++ )
for(int j = 1; j <= n; j++ )
f[i][j] = max(f[i - 1][j], f[i][j - 1]) + w[i][j];
//f[i][j]为上一步最大值加上w[i][j]的花生数目
cout << f[m][n] << endl;
}
return 0;
}
3.最长上升子序列 895
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int a[maxn], b[maxn];
int n, res;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++ )cin >> a[i];
for(int i = 1; i <= n; i++ )
{
b[i] = 1;
for(int j = 1; j < i; j++ )
if(a[j] < a[i]) b[i] = max(b[i], b[j] + 1);
res = max(res, b[i]);
}
cout << res << endl;
return 0;
}
4.地宫取宝 1212
这题是最大上升子序列加上摘花生的结合版本,要考虑的东西变多了。
1.要考虑每次拿的宝物的价值与最大上升子序列类似,只不过序列数是固定的
2.4维dp,i j k v 分别表示从起点走到坐标i j,捡起来了k件宝物,宝物的最大价值是v
3.起点的初始化问题
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 55, MOD = 1e9 + 7;
int w[maxn][maxn];
int f[maxn][maxn][13][14];
int n, m, k;
int main()
{
cin >> m >> n >> k;
for(int i = 1; i <= m; i++ )
for(int j = 1; j <= n; j++ )
{
scanf("%d", &w[i][j]);
w[i][j]++;
}
f[1][1][0][0] = 1;//初始化
f[1][1][1][w[1][1]] = 1;
for(int i = 1; i <= m; i++ )
for(int j = 1; j <= n; j++ )
{
if(i == 1 && j == 1) continue;//因为[1][1]已经初始化过,可无
for(int u = 0; u <= k; u++ )
for(int v = 0; v <= 13; v++ )
{
int &val = f[i][j][u][v];//引用使代码看起来简洁
//不选w[i][j]的两种情况
val = (val + f[i - 1][j][u][v]) % MOD;
val = (val + f[i][j - 1][u][v]) % MOD;
if(u > 0 && v == w[i][j])//选w[i][j]的两种情况
{
for(int c = 0; c < v; c++ )
{
val = (val + f[i - 1][j][u - 1][c]) % MOD;
val = (val + f[i][j - 1][u - 1][c]) % MOD;
}
}
}
}
int res = 0;
for(int v = 0; v <= 13; v ++ ) res = (res + f[m][n][k][v]) % MOD;
cout << res << endl;
return 0;
}
5.波动数列 1214
设第一项为x,di 为+a或者-b,则序列可以表示为:
x , x + d1, x + d1 + d2, ... , x + d(n-1)
则s = n * x + (n - 1)d1 + (n - 2)d2 + ... + d(n - 1)
因为x的取值范围为R,因此想到用其他变量表示x,而且方面起见,将d的序号反过来
x = [s - (d1 + 2d2 + 3d3 + ... + (n - 1)d(n - 1))] / n
首先可以知道一组合法的di序列对应一个唯一的x,所以题目问题也就是问有多少组合法的di序列
其次因为x是整数,所以又可以转换为有多少组di序列使得上式的分子mod n余数相等
//f[i][j]表示前i组di序列mod n的余数为j的序列数的总和
//设前i-1项mod n为c,则f[i][j]项mod n的值就是 c + i * a = j mod n,
//因此c为(j - a * i) mod n
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1010, MOD = 100000007;
int f[maxn][maxn];//第二维表示mod n为 j的序列和
int get_mod(int x, int y)//确保mod的余数全部为整数,防止数组越界
{
return (x % y + y) % y;
}
int main()
{
int n, s, a, b;
cin >> n >> s >> a >> b;
f[0][0] = 1;//初始化
for(int i = 1; i < n; i++ )
for(int j = 0; j < n; j ++ )
f[i][j] = (f[i - 1][get_mod(j - a * (n - i), n)] + f[i - 1][get_mod(j + b * (n - i), n)]) % MOD;
//最后要输出的是前n - 1 项序列和mod n的数值为 get_mod(s, n)的合法序列数目
cout << f[n - 1][get_mod(s, n)] << endl;
return 0;
}
Chapter3数学与简单DP的更多相关文章
- HDU 1087 简单dp,求递增子序列使和最大
Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 ...
- Codeforces Round #260 (Div. 1) A. Boredom (简单dp)
题目链接:http://codeforces.com/problemset/problem/455/A 给你n个数,要是其中取一个大小为x的数,那x+1和x-1都不能取了,问你最后取完最大的和是多少. ...
- codeforces Gym 100500H A. Potion of Immortality 简单DP
Problem H. ICPC QuestTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100500/a ...
- 简单dp --- HDU1248寒冰王座
题目链接 这道题也是简单dp里面的一种经典类型,递推式就是dp[i] = min(dp[i-150], dp[i-200], dp[i-350]) 代码如下: #include<iostream ...
- poj2385 简单DP
J - 简单dp Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:65536KB 64bit ...
- hdu1087 简单DP
I - 简单dp 例题扩展 Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:32768KB ...
- poj 1157 LITTLE SHOP_简单dp
题意:给你n种花,m个盆,花盆是有顺序的,每种花只能插一个花盘i,下一种花的只能插i<j的花盘,现在给出价值,求最大价值 简单dp #include <iostream> #incl ...
- hdu 2471 简单DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2571 简单dp, dp[n][m] +=( dp[n-1][m],dp[n][m-1],d[i][k ...
- Codeforces 41D Pawn 简单dp
题目链接:点击打开链接 给定n*m 的矩阵 常数k 以下一个n*m的矩阵,每一个位置由 0-9的一个整数表示 问: 从最后一行開始向上走到第一行使得路径上的和 % (k+1) == 0 每一个格子仅仅 ...
随机推荐
- Selenium(七):截图显示等待
一.显示等待(有条件等待) 常见问题: 定位明明是对的,为什么运行代码没找到定位. 定位明明是对的,找到定位了,文本信息为什么取到是空的? 分析原因: 没有处理frame 页面渲染速度比自动化测试的代 ...
- idea 2019.3 破解激活码
idea激活码(亲测 idea 2019.3可用)有效期到2021年3月: QYYBAC9D3J-eyJsaWNlbnNlSWQiOiJRWVlCQUM5RDNKIiwibGljZW5zZWVOYW1 ...
- Matlab 与 c++对txt 文档的读写格式
学习g++能够读取什么格式的txt文件. 读基本指令: >sprintf(filename, "doc_%d.txt", d); >fileptr = fopen(fi ...
- ThreadLocalRandom ---- 提升Random在大并发下的效率
本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 随机数 随机数在科学研究与工程实际中有着极其重要的应用! ...
- SQL Server 常用的数据类型
1. 字符串数据类型 char 此数据类型可存储1~8000个定长字符串,字符串长度在创建时指定:如未指定,默认为char(1).每个字符占用1byte存储空间. nchar ...
- HDU6446 Tree and Permutation(树、推公式)
题意: 给一棵N个点的树,对应于一个长为N的全排列,对于排列的每个相邻数字a和b,他们的贡献是对应树上顶点a和b的路径长,求所有排列的贡献和 思路: 对每一条边,边左边有x个点,右边有y个点,x+y= ...
- [redis读书笔记] 第一部分 数据结构与对象 字典
三 字典 字典是Hash对象的底层实现,比如用HSET创建一个HASH的对象,底层可能就是用一个字典实现的键值对. 字典的实现主要设计下面三个结构: /* * 哈希表节点 */ typedef str ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统--网页版本代码生成器
1.单列表模式 2.树形列表模式 3.左右列表模式 4.左右树形和列表结合模式 一 简介 网页版代码生成器需要运行项目,非常有趣,可以用来研究,和自定义一些自己的代码习惯 按界面生成:可生成单个页面和 ...
- 1 Nginx + 12 Tomcat +2DB 实现2个程序负载均衡
根据真实生产环境 总结. 硬件:共计5台服务器 1台负载windows.2台业务windows.2台数据库linux 业务:运行两个程序,两个数据库 具体:63服务器安装 Nginx 做负载 :61 ...
- FakeLogonScreen抓取Windows凭证
FakeLogonScreen抓取Windows凭证 实践中使用的配置 攻击者: 操作系统: Kali Linux 2020.1 IP: 192.168.1.13 目标: 作业系统: Windows ...