专栏文章
题解:CF1067D Computer Game
CF1067D题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @miq9yxhs
- 此快照首次捕获于
- 2025/12/04 01:22 3 个月前
- 此快照最后确认于
- 2025/12/04 01:22 3 个月前
Computer Game
可以发现赢下一局后,会选择升级后期望收益 最高的一种游戏玩到结束位置,记 为 。接下来考虑升级前的策略,由于不能找出直观的贪心策略,那就使用动态规划。设 表示游戏还剩 秒且在此之前没有赢过的期望收益最大值。可以列出转移方程:
这样直接转移是 的,因此要优化转移。
首先把常量扔外面,再按照 整理式子:
由于转移的时候 是已知的,在一步转移中可以视为常量。而 也是已知常量,所以 在一步转移中也可以视为常量。关于 的变量 ,与转移的量相乘与相加,这种形式可以用使用斜率优化。还有不懂斜率优化的同学可以看这里。
然后显然有 ,所以 ,即式子中的 是递增的,因此可以用单指针来维护最优解在凸包上的位置,即转移是 的。
此时的复杂度就变成了 。
然后由于 递增,所以游戏 作为最优解的时刻一定是一个区间,则对于每一段连续的区间,可以使用矩阵加速转移。即:
然后使用矩阵倍增,就可以在 的时间内转移一段连续的区间了。总时间复杂度 。
Code
CPP#include <iostream>
#include <algorithm>
#include <string.h>
#include <iomanip>
#include <bitset>
#include <math.h>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#define fst first
#define scd second
#define db double
#define ll long long
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector <int>
#define pii pair <int, int>
#define sz(x) ((int)x.size())
#define ms(f, x) memset(f, x, sizeof(f))
#define L(i, j, k) for (int i=(j); i<=(k); ++i)
#define R(i, j, k) for (int i=(j); i>=(k); --i)
#define ACN(i, H_u) for (int i=H_u; i; i=E[i].nxt)
using namespace std;
template <typename INT> void rd(INT &res) {
res=0; bool f=false; char ch=getchar();
while (ch<'0'||ch>'9') f|=ch=='-', ch=getchar();
while (ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^48), ch=getchar();
res=(f?-res:res);
}
template <typename INT, typename...Args>
void rd(INT &x, Args &...y) { rd(x), rd(y...); }
//dfs
const int maxn=1e5;
const int N=maxn+10;
int n, stk[N], top; ll tv; db V;
//wmr
struct node {
db x, y;
bool operator < (const node &k) const { return x<k.x; }
} g[N];
struct matrix {
db f[3][3];
matrix() { L(i, 0, 2) L(j, 0, 2) f[i][j]=0; }
void unit() { f[0][0]=f[1][1]=f[2][2]=1; }
} bin[40];
matrix operator * (const matrix &x, const matrix &y) {
matrix z;
L(k, 0, 2) L(i, 0, 2) L(j, 0, 2) z.f[i][j]+=x.f[i][k]*y.f[k][j];
return z;
}
// db slope(int i, int j) { return (g[j].y-g[i].y)/(g[j].x-g[i].x); }
//incra
//lottle
signed main() {
// ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
freopen("CF1067D.in", "r", stdin);
freopen("CF1067D.out", "w", stdout);
rd(n, tv);
L(i, 1, n) {
int a, b; db p;
rd(a, b); scanf("%lf", &p);
V=max(V, p*b); g[i].x=p, g[i].y=p*a;
}
sort(g+1, g+n+1);
L(i, 1, n) {
// while (top>1&&slope(i, stk[top])>=slope(stk[top], stk[top-1])) --top;
while (top>1&&(g[i].y-g[stk[top]].y)*(g[stk[top]].x-g[stk[top-1]].x)>=(g[stk[top]].y-g[stk[top-1]].y)*(g[i].x-g[stk[top]].x)) --top;
stk[++top]=i;
}
matrix res; res.f[0][2]=1; ll t=0;
L(i, 1, top) {
db val=t*V-res.f[0][0];
// while (i<top&&-val<=slope(stk[i], stk[i+1])) ++i;
while (i<top&&g[stk[i+1]].y-g[stk[i]].y+val*(g[stk[i+1]].x-g[stk[i]].x)>=0) ++i;
bin[0].f[0][0]=1-g[stk[i]].x, bin[0].f[1][0]=g[stk[i]].x*V, bin[0].f[2][0]=g[stk[i]].y, bin[0].f[1][1]=bin[0].f[2][1]=bin[0].f[2][2]=1;
int uj=__lg(tv-t);
L(j, 1, uj) bin[j]=bin[j-1]*bin[j-1];
R(j, uj, 0) if (t+(1ll<<j)<tv) {
matrix tmp=res*bin[j]; val=(t+(1ll<<j))*V-tmp.f[0][0];
// if (i==top||-val>=slope(stk[i], stk[i+1])) res=tmp, t+=(1ll<<j);
if (i==top||g[stk[i+1]].y-g[stk[i]].y+val*(g[stk[i+1]].x-g[stk[i]].x)<=0) res=tmp, t+=(1ll<<j);
}
res=res*bin[0], ++t;
if (t==tv) break;
}
printf("%.12lf\n", res.f[0][0]);
return 0;
}
/*
input
4 1000000
2 3 0.00001
3 100 0.000004
5 1000 0.000001
8 3000 0.0000004
output
1082.0053569238542
*/
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...