2019.5.3&4高中部集训
- 这次因为期中考没去,现在发现这次学的好难啊,应该是一直在做题吧
知识清单
- 动态规划
笔记&&解题报告
基本问题:
背包(似乎没讲)- 最长上升子序列
- :最暴力算法直接,查找前面可转移的最长上升序列转移,这一查找步骤使用
for
,所以慢。 - :使用一个栈来储存转移点,如果一个数比栈中所有数大,直接压入,否则找到相应的位置替换,这样寻找转移点可以直接二分(),栈中的元素满足单调性。
- :最暴力算法直接,查找前面可转移的最长上升序列转移,这一查找步骤使用
- 最大子段和
- :分为贪心和,
可以理解为一个背包问题(即捡或不捡)(不能这么理解,中途不捡就不是子段了),扫一遍即可,更新最大值。 - :数据结构,不过这种适用于动态查询,即可能被修改。
- :分为贪心和,
- 最长公共子序列
例题
逆序对数列
分析:(上次写过这道题(SP64))那道题和这道题不一样的,这道题还带一个前缀和优化。可以发现,朴素的做法是 的,在这道题的数据会超时。然后又会发现,第 3 层循环的作用就是把 加起来,所以说可以想到前缀和的做法。详情见题解。
还有,记得要取模!
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 1e3+5;
const int Mod = 1e4;
int n, k, f[MAXN][MAXN];
int main() {
scanf ("%d%d",&n,&k);
f[1][0]=1;
for (int i=2; i<=n; i++) {
int sum = 0;
for (int j=0; j<=k; j++) {
sum += f[i-1][j];
sum %= Mod;
f[i][j]=sum;
if ( j-i+1 >= 0 ) {
sum = ( sum-f[i-1][j-i+1]+Mod )%Mod;
}
}
}
printf ("%d\n",f[n][k]);
return 0;
}
最长公共子序列: 上面写过了
[[]股票交易](https://www.luogu.org/problemnew/show/P2569)
分析:懒得写了(根本不会),的题解。然后老师上列了一个转移方程:(雾)
时间复杂度:
添加括号
分析:发现这道题让你添加括号就是改变合并顺序,所以想到区间,区间最经典的题就是石子合并,这题也是只让你合并相邻的两个,计算最小代价。
[[]三国围棋对抗赛](https://www.luogu.org/problemnew/show/P2531)
分析:这题挺冷的,没什么人做,看到数据范围就可以先想到用“暴力”了,这题算的全是概率,所以什么时候加,什么时候乘不要搞错了,前面有个轮空规则不要忘了(应该不会吧),然后差不多就是一个接近于模拟的一个。众所周知,可以使用任何方法,递归也是可以的,就像上次学校考试中的,使用的就是(递归)。
#include <cstdio>
#include <iostream>
using namespace std;
double data[16][11],b[6][6],win[6][6][6],f[3][7][7][7];
int t,n;
double ans=0,tot=0;
bool book[16];
void dfs(int p) {
if(p>5) {
f[0][1][1][1]=f[1][1][1][1]=f[2][1][1][1]=1.0/3.0;
for(int i=1; i<=6; i++) {
for(int j=1; j<=6; j++) {
for(int k=1; k<=6; k++) {
if(i>1) {
f[0][i][j][k]=f[1][i-1][j][k]*win[4][k][i-1]+f[2][i-1][j][k]*win[2][j][i-1];
if(i==6)
f[0][i][j][k]+=f[0][i][j-1][k]*win[5][k][j-1]+f[0][i][j][k-1]*win[3][j][k-1];
}
if(j>1) {
f[1][i][j][k]=f[0][i][j-1][k]*win[5][k][j-1]+f[2][i][j-1][k]*win[0][i][j-1];
if(j==6)
f[1][i][j][k]+=f[1][i-1][j][k]*win[4][k][i-1]+f[1][i][j][k-1]*win[1][i][k-1];
}
if(k>1) {
f[2][i][j][k]=f[0][i][j][k-1]*win[3][j][k-1]+f[1][i][j][k-1]*win[1][i][k-1];
if(k==6)
f[2][i][j][k]+=f[2][i-1][j][k]*win[2][j][i-1]+f[2][i][j-1][k]*win[0][i][j-1];
}
}
}
}
tot=0;
for(int i=1; i<=5; i++) {
tot+=f[1][i][6][6];
}
ans=max(ans,tot);
return;
}
int l,r;
for(l=1; l<=n; l++) {
if(!book[l]) {
book[l]=true;
for(r=1; r<=5; r++) {
win[0][p][r]=data[l][r];
win[2][r][p]=1.0-data[l][r];
}
for(r=1; r<=5; r++) {
win[1][p][r]=data[l][r+5];
win[4][r][p]=1.0-data[l][r+5];
}
dfs(p+1);
book[l]=false;
}
}
return;
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n; i++)
for(int j=1; j<=10; j++)
scanf("%lf",&data[i][j]);
for(int i=1; i<=5; i++) {
for(int j=1; j<=5; j++) {
scanf("%lf",&b[i][j]);
win[3][i][j]=b[i][j];
win[5][j][i]=1.0-b[i][j];
}
}
dfs(1);
printf("%.6lf\n",ans);
return 0;
}