CF553E Kyoya and Train

2024-04-30 23:08
文章标签 train kyoya cf553e

本文主要是介绍CF553E Kyoya and Train,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

给定一张 n 个点 m 条边的无重边无自环的有向图,你要从 1 号点到 n 号点去。
如果你在 t 时刻之后到达n 号点,你要交 x 元的罚款。
每条边从 a i a_i ai b i b_i bi ,走过它需要花费 c i c_i ci元,多次走过同一条边需要多次花费。
走过每条边所需的时间是随机的,对于 k∈[1,t], p i , k 1 0 5 \dfrac{p_{i,k}}{10^5} 105pi,k 表示走过第 i 条边需要时间 k 的概率。因此如果多次走过同一条边,所需的时间也可能不同。
你希望花费尽可能少的钱(花费与罚款之和)到达 n 号点,因此每到达一个点,你可能会更改原有的计划。
求在最优决策下,你期望花费的钱数。
n ≤ 50 , m ≤ 100 , t ≤ 2 × 1 0 4 , x , c i ≤ 1 0 6 , ∑ k = 1 t p i , k = 1 0 5 n \leq 50,m \leq 100,t \leq 2 \times 10^4,x,c_i \le 10^6 ,\sum_{k=1}^t p_{i,k} = 10^5 n50m100t2×104x,ci106,k=1tpi,k=105 ,答案精度误差 ≤ 1 0 − 6 \leq 10^{-6} 106


Solution

FFT优化spfa多状态转移

正着设初始状态并不对劲,正难则反。
算了 我⑧说了 看这里罢

还是很能体现概率期望的灵活性。

转移时其实只有后面的时间能够影响前面的时间,其实是一个分层转移。那么我们可以通过CDQ分治时间计算,时间复杂度为 O ( m t l o g 2 t ) O(mtlog^2t) O(mtlog2t)

这里写的是sb做法,直接FFT转移SPFA,时间复杂度 O ( n m t l o g t ) O(nmtlogt) O(nmtlogt)
dijkstra的话因为无法有效比较两个状态的优劣(第二维时间太多)而没法写


Code

#include<bits/stdc++.h>
using namespace std;
struct edge{int y,z,nxt;
}e[110];
int head[60],cnt;
void add(int x,int y,int z){cnt++;e[cnt].y=y;e[cnt].z=z;e[cnt].nxt=head[x];head[x]=cnt;
}
long long d[60];
bool vis[60];
struct data{int x;long long s;bool operator <(const data &v)const{return s>v.s;}
};
priority_queue<data>q1;
const double pi=acos(-1.0);
int n,m,t,S,bit,limit=1,rev[200010];
struct cp{double x,y;cp(double xx=0,double yy=0){x=xx,y=yy;}
}a[200010],b[200010],c[200010];
double p[110][200010],dis[60][200010];
cp operator + (cp u,cp v){return cp(u.x+v.x,u.y+v.y);		
}
cp operator - (cp u,cp v){return cp(u.x-v.x,u.y-v.y);		
}
cp operator * (cp u,cp v){return cp(u.x*v.x-u.y*v.y,u.x*v.y+u.y*v.x);	
}
void dijkstra(){for(int i=1;i<n;i++) d[i]=1e15;q1.push((data){n,0});while(!q1.empty()){data x=q1.top();q1.pop(),vis[x.x]=0;for(int i=head[x.x];i;i=e[i].nxt){int y=e[i].y,z=e[i].z;if(d[y]>d[x.x]+z){d[y]=d[x.x]+z;if(!vis[y]){q1.push((data){y,d[y]});vis[y]=true;}}}}//for(int i=1;i<=n;i++)//cout<<i<<" "<<d[i]<<endl;
}
void FFT(cp *A,int type){for(int i=0;i<limit;i++)if(i<rev[i]) swap(A[i],A[rev[i]]);for(int mid=1;mid<limit;mid<<=1){cp wn(cos(pi/mid),type*sin(pi/mid));for(int r=mid<<1,j=0;j<limit;j+=r){cp w(1,0);for(int k=0;k<mid;k++,w=w*wn){cp x=A[j+k],y=w*A[j+mid+k];A[j+k]=x+y,A[j+mid+k]=x-y;}	}}if(type==-1)for(int i=0;i<limit;i++)A[i].x/=limit;
}
void mul(double *A,double *B){for(int i=0;i<=2*t;i++)a[i]=cp(A[i],0),b[i]=cp(B[i],0);//,cout<<a[i].x<<" "<<b[i].x<<endl;;for(int i=2*t+1;i<limit;i++)a[i]=b[i]=cp(0,0);FFT(a,1),FFT(b,1);for(int i=0;i<limit;i++)c[i]=a[i]*b[i]; FFT(c,-1);
}
queue<int>q2; 
void spfa(){for(int i=1;i<=n;i++){for(int j=0;j<=t;j++)dis[i][j]=1e15;for(int j=t+1;j<=2*t;j++)dis[i][j]=d[i]+S; }for(int j=0;j<=t;j++)dis[n][j]=0;q2.push(n);while(!q2.empty()){int x=q2.front();q2.pop(),vis[x]=0;for(int i=head[x];i;i=e[i].nxt){int y=e[i].y,z=e[i].z;mul(dis[x],p[i]);bool flag=false;for(int j=0;j<=t;j++)if(dis[y][j]>c[t+j+1].x+z){dis[y][j]=c[t+j+1].x+z;flag=true;}if(flag&&!vis[y]){q2.push(y);vis[y]=1;}}}
}
int main(){int x,y,z;scanf("%d%d%d%d",&n,&m,&t,&S);for(int i=1;i<=m;i++){scanf("%d%d%d",&x,&y,&z);add(y,x,z);for(int j=1;j<=t;j++){scanf("%lf",&p[i][j]);p[i][j]/=100000;}reverse(p[i]+1,p[i]+t+1);}dijkstra();while(limit<=4*t)limit<<=1,bit++;for(int i=0;i<limit;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));spfa();//for(int i=0;i<=2*t;i++)printf("%.10lf",dis[1][0]);
}

这篇关于CF553E Kyoya and Train的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/950160

相关文章

【chatgpt】train_split_test的random_state

在使用train_test_split函数划分数据集时,random_state参数用于控制随机数生成器的种子,以确保划分结果的可重复性。这样,无论你运行多少次代码,只要使用相同的random_state值,得到的训练集和测试集划分就会是一样的。 使用 train_test_split 示例 以下是一个示例,展示如何使用train_test_split函数进行数据集划分,并设置random_s

tf.train.batch和tf.train.shuffle_batch的理解

capacity是队列的长度 min_after_dequeue是出队后,队列至少剩下min_after_dequeue个数据 假设现在有个test.tfrecord文件,里面按从小到大顺序存放整数0~100 1. tf.train.batch是按顺序读取数据,队列中的数据始终是一个有序的队列, 比如队列的capacity=20,开始队列内容为0,1,..,19=>读取10条记录后,队列剩下10,

ValueError: Shape must be rank 0 but is rank 1 for 'train_data/ReadFile' (op: 'ReadFile') with input

使用函数tf.train.slice_input_producer读取文件时, input_queue = tf.train.slice_input_producer([flist], shuffle=self.shuffle,seed=0123, num_epochs=self.num_epochs)input_file = tf.read_file(input_queue) 出现错误:

train订票系统优化最终版

.h文件#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>#include <string.h>struct train {//车次的属性int id;char name[50];int remainTickets;};struct node {//普通节点的属性struct node *next;st

caffe CNN train_val.prototxt 神经网络参数配置说明

name: "CaffeNet"layer {#输入层,即数据层#数据层的类型除了Database外,还可以是In-Memory、HDF5 Input、HDF5 Output、Images、Windows、Dummyname: "data"type: "Data"top: "data"top: "label"include {phase: TRAIN#表示仅在训练阶段包括进去

Sklearn工具包---train_test_split随机划分训练集和测试集

一般形式: train_test_split是交叉验证中常用的函数,功能是从样本中随机的按比例选取train data和test data,形式为: X_train,X_test, y_train, y_test = cross_validation.train_test_split(train_data,train_target,test_size=0.4, random_stat

model.train及model.eval

链接:model.train()及model.eval()

tensorflow中 tf.train.slice_input_producer() 函数和 tf.train.batch() 函数

原创:https://blog.csdn.net/dcrmg/article/details/79776876 别人总结的转载方便自己以后看 tensorflow数据读取机制 tensorflow中为了充分利用GPU,减少GPU等待数据的空闲时间,使用了两个线程分别执行数据读入和数据计算。 具体来说就是使用一个线程源源不断的将硬盘中的图片数据读入到一个内存队列中,另一个线程负责

codeforces 553A Kyoya and Colored Balls 组合数学

题意: 有k种球,每种球有a[i]个。现在它们都放到一个袋子里,要求取出来的时候,第i种球完全取出来要在第i+1种球前面。问你有多少种取法。 思路: 比赛时没想出来。。。结果其实是很简单的。 倒过来统计就好了。 假设n = sum(a[i]); 首先先看第k种球,如果先把其中一个球放到最后一个位置,那么剩下的a[k]-1个球就是随便放,则有c[n-1][a[k]-1]种放法。

tf.estimator.train_and_evaluate() 训练与测试不一致

问题背景 以一个简单的分类任务为例,在处理完数据之后,使用如下code进行训练: estimator = tf.estimator.Estimator(model_fn, 'model', cfg, params)train_spec = tf.estimator.TrainSpec(input_fn=train_inpf, hooks=[])eval_spec = tf.estimato