NOIP模拟测试29(A)
T1:
题目大意:有一张有向无环图,第$x$次经过边$i$的代价为$a_ix+b_i$,最多经过$c_i$次,起点为1,$s$个点可作为终点,求走$k$次的最小代价。
我们新建一个汇点,将所有可做为终点的边到汇点连边,那么本题便成为了费用流模型。
贪心策略为:每次走最短路。
证明:路径的顺序是可以改变的,设每次走的路径代价是递增的,如果当前不走最短路,那么以后不可能有一条路能将代价追回,所以当前走最短路一定最优。
但是每次增广代价是不同的,我们只能进行完一次增广之后立即修改边权。
考虑EK,每次用spfa找一条代价最小的增广路,并更新费用即边权,若当前边是正向边,则将正向边权加$a_i$,反向边权减$a_i$,反之将正向边权减$a_i$,反向边权加$a_i$。正向边初始权值为$a_i+b_i$,由于反向边退流退的是上一层的费用,所以初值应赋为$-b_i$。
然后增广k次,若流量不能达到k,输出-1。
spfa复杂度视为$O(NM)$时,时间复杂度$O(NMK)$,但远远达不到。
Code:
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=;
const int M=;
const int inf=1e9+;
int n,m,k,s,nm=,ans=;
int fi[N],p[N],d[N];
bool v[N];
struct edge{
int v,ne;
int l,a,b;
}e[M+N<<];
queue<int> q;
int read()
{
int s=;char c=getchar();
while(c<''||c>'') c=getchar();
while(c>=''&&c<=''){
s=(s<<)+(s<<)+c-'';
c=getchar();
}
return s;
}
void add(int x,int y,int z1,int z2,int z3)
{
e[++nm].v=y;e[nm].a=z1;e[nm].b=z1+z2;
e[nm].l=z3;e[nm].ne=fi[x];fi[x]=nm;
e[++nm].v=x;e[nm].a=-z1;e[nm].b=-z2;
e[nm].l=;e[nm].ne=fi[y];fi[y]=nm;
}
bool spfa()
{
for(int i=;i<=n;i++){
p[i]=;d[i]=inf;v[i]=false;
}
while(!q.empty()) q.pop();
d[]=;v[]=true;q.push();
while(!q.empty()){
int x=q.front();q.pop();
v[x]=false;
for(int i=fi[x];i!=;i=e[i].ne){
int y=e[i].v;
if(e[i].l==) continue;
if(d[y]>d[x]+e[i].b){
d[y]=d[x]+e[i].b;p[y]=i;
if(!v[y]){
v[y]=true;q.push(y);
}
}
}
}
if(d[n]<inf) return true;
else return false;
}
void update()
{
int x=n;ans+=d[n];
while(x!=){
int y=p[x];
if((y&)==) e[y].b+=e[y].a,e[y^].b+=e[y^].a;
else e[y].b-=e[y].a,e[y^].b-=e[y^].a;
e[y].l-=;e[y^].l+=;
x=e[y^].v;
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&s);
n++;
for(int i=;i<=s;i++){
int x=read();
add(x,n,,,inf);
}
for(int i=;i<=m;i++){
int x=read(),y=read(),a=read(),b=read(),c=read();
add(x,y,a,b,c);
}
int tot=;
while(tot<k&&spfa()){
update();tot++;
}
if(tot!=k) printf("-1\n");
else printf("%d\n",ans);
return ;
}
T1
T2:
题目大意:有两串数字x和y,以及n串数字段,求$[x+1,y]$内至少含有n个数字段的数的个数,对$1e9+7$取模。
一个数字段可以被包含多次,重复的数字段也要重复计算。
由区间可以看出此题为数位DP,然后发现字串包含,于是想AC自动机。
然后这道题变为了AC自动机上的数位DP。
按照数位DP方法,我们先求出$[1,y]$中合法解的个数,再减去$[1,x]$中合法解的个数,即为答案。
建出AC自动机,每个点的权值为以该节点为结尾的串的数量,用trie图优化,注意每个节点要继承fail的信息。
设$dp[i][j][k][0/1]$,代表匹配到第i位,在节点j,匹配了k个子串的方案数,1代表有限制,0代表无限制。
对于每个数,有无前缀0与其大小无关,于是我们可以带着前缀0进行DP转移。
设$S$为指向$x$的点集,$w[i]$为节点i的权值,$t[i]$为节点i的类型,$a$为较大的边界,则:
$dp[i][x][j][0]= \sum _{y \in S} dp[i-1][y][j-w[x]][0]+[t[x]<a[i]]* \sum _{y \in S} dp[i-1][y][j-w[x]][1]$
$dp[i][x][j][1]=[t[x]==a[i]]* \sum _{y \in S} dp[i-1][y][j-w[x]][1]$
由于没有考虑前缀0影响,统计答案时只累加长度等于原串的答案即可。
时间复杂度$O(NSK)$,$S$为子串总长。
Code:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<queue>
#define LL long long
using namespace std;
const LL mod=1e9+;
int n,k,rt=,cnt=;
string s;
int a[][];
LL dp[][][][];
bool v[][][][];
struct trie{
int ch[],fail;
int e;
}t[];
queue<int> q,q1,q2,q3,q4;
void insert()
{
int now=rt;
for(int i=;i<s.size();i++){
int x=s[i]-'';
if(t[now].ch[x]==)
t[now].ch[x]=++cnt;
now=t[now].ch[x];
}
t[now].e++;
}
void build()
{
for(int i=;i<=;i++){
if(t[rt].ch[i]!=) q.push(t[rt].ch[i]);
}
while(!q.empty()){
int x=q.front();q.pop();
for(int i=;i<=;i++){
if(t[x].ch[i]!=){
t[t[x].ch[i]].fail=t[t[x].fail].ch[i];
t[t[x].ch[i]].e+=t[t[t[x].fail].ch[i]].e;
q.push(t[x].ch[i]);
}
else t[x].ch[i]=t[t[x].fail].ch[i];
}
}
}
LL work(int id)
{
memset(dp,,sizeof(dp));
memset(v,false,sizeof(v));
while(!q1.empty()){
q1.pop();q2.pop();q3.pop();q4.pop();
}
dp[][rt][][]=;v[][rt][][]=true;
q1.push();q2.push(rt);q3.push();q4.push();
while(!q1.empty()){
int x=q1.front(),y=q2.front(),z=q3.front(),op=q4.front();
v[x][y][z][op]=false;
q1.pop();q2.pop();q3.pop();q4.pop();
if(x==a[id][]) break;
for(int i=;i<=((op&)==?a[id][x+]:);i++){
int yy=t[y].ch[i];int zz=z+t[yy].e;
if(zz>k) zz=k;
if((op&)==&&i==){
if((op&)==&&i==a[id][x+]){
dp[x+][yy][zz][]=(dp[x+][yy][zz][]+dp[x][y][z][op])%mod;
if(!v[x+][yy][zz][]){
q1.push(x+);q2.push(yy);q3.push(zz);q4.push();
v[x+][yy][zz][]=true;
}
}
else{
dp[x+][yy][zz][]=(dp[x+][yy][zz][]+dp[x][y][z][op])%mod;
if(!v[x+][yy][zz][]){
q1.push(x+);q2.push(yy);q3.push(zz);q4.push();
v[x+][yy][zz][]=true;
}
}
}
else{
if((op&)==&&i==a[id][x+]){
dp[x+][yy][zz][]=(dp[x+][yy][zz][]+dp[x][y][z][op])%mod;
if(!v[x+][yy][zz][]){
q1.push(x+);q2.push(yy);q3.push(zz);q4.push();
v[x+][yy][zz][]=true;
}
}
else{
dp[x+][yy][zz][]=(dp[x+][yy][zz][]+dp[x][y][z][op])%mod;
if(!v[x+][yy][zz][]){
q1.push(x+);q2.push(yy);q3.push(zz);q4.push();
v[x+][yy][zz][]=true;
}
}
}
}
}
LL ans=;
for(int j=;j<=cnt;j++){
ans=(ans+dp[a[id][]][j][k][])%mod;
ans=(ans+dp[a[id][]][j][k][])%mod;
}
return ans;
}
int main()
{
scanf("%d%d",&n,&k);
cin>>s;a[][]=s.size();
for(int i=;i<=a[][];i++) a[][i]=s[i-]-'';
cin>>s;a[][]=s.size();
for(int i=;i<=a[][];i++) a[][i]=s[i-]-'';
for(int i=;i<=n;i++){
cin>>s;insert();
}
build();
LL ans=work();
ans-=work();
ans=(ans%mod+mod)%mod;
printf("%lld\n",ans);
return ;
}
T2
NOIP模拟测试29(A)的更多相关文章
- 8.22 NOIP模拟测试29(B) 爬山+学数数+七十和十七
T1 爬山 二分最高高度,$O(1)$判断是否可行. #include<iostream> #include<cstdio> #define ll long long usin ...
- NOIP模拟测试29「爬山·学数数·七十和十七」
爬山题解不想写了 学数数 离散化然后找到以每一个值为最大值的连续子段有多少个,然后开个桶维护 那么怎么找以每一个值为最大值的连续子段个数 方法1(我的极笨的方法) 考试时我的丑陋思路, 定义极左值为左 ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色
2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
- NOIP模拟测试17&18
NOIP模拟测试17&18 17-T1 给定一个序列,选取其中一个闭区间,使得其中每个元素可以在重新排列后成为一个等比数列的子序列,问区间最长是? 特判比值为1的情况,预处理比值2~1000的 ...
- 2019.7.29 NOIP模拟测试10 反思总结【T2补全】
这次意外考得不错…但是并没有太多厉害的地方,因为我只是打满了暴力[还没去推T3] 第一题折腾了一个小时,看了看时间先去写第二题了.第二题尝试了半天还是只写了三十分的暴力,然后看到第三题是期望,本能排斥 ...
- 「题解」NOIP模拟测试题解乱写I(29-31)
NOIP模拟29(B) T1爬山 简单题,赛时找到了$O(1)$查询的规律于是切了. 从倍增LCA那里借鉴了一点东西:先将a.b抬到同一高度,然后再一起往上爬.所用的步数$×2$就是了. 抬升到同一高 ...
随机推荐
- leetcode-第14周双周赛-1273-删除树节点
题目描述: 自己的提交:动态规划 class Solution: def deleteTreeNodes(self, nodes: int, parent: List[int], value: Lis ...
- [CSP-S模拟测试58]题解
以后题解还是单独放吧. A.Divisors 根号筛求所有数的因子,扫一遍去重统计即可. #include<cstdio> #include<iostream> #includ ...
- 【从0到1,搭建Spring Boot+RESTful API+Shiro+Mybatis+SQLServer权限系统】02、创建新的SpringBoot项目
1.创建项目 得到项目架构 2.测试项目Web功能 默认端口为8080,运行后,输入localhost:8080/index即可访问到网页 到这里,项目构建成功!
- Redis入门很简单之三【常见参数配置】
Redis入门很简单之三[常见参数配置] 博客分类: NoSQL/Redis/MongoDB redisnosql缓存中间件memcached Redis的一下常见设置都是通过对redis.conf ...
- windows10下Mysql5.7安装指南
背景 值此国庆70周年之际,为了发扬广大国内软件开发行业,我决定使用MySQL5.7. 呸!实际情况是公司的项目用的是Mysql5.7,但是正式服务器在国外,而且测试服务器也是在国外,关键问题是我这个 ...
- 调整WebBrowser的默认浏览器内核版本
原文出自:https://my.oschina.net/Tsybius2014/blog/492107 注:这个是写.net控件,其实delphi是一样的.作者已经写的比较全面了,我只是做了一点修改 ...
- 关于audio不能拖放
图一,图二均为wav格式文件 图一为播放本地的音频,可以拖放 图二为放在后台的音频,不可以拖放 把这两个图片发给后台,让后台分析下两个的headers不同之处
- #include和前置声明(forward declaration)
#include和前置声明(forward declaration) 1. 当不需要调用类的实现时,包括constructor,copy constructor,assignment opera ...
- 8.Jmeter 快速入门教程 -- 如何使测试脚本更强大
添加基本的elements例如Sampler 或者一些监听器,就可以完成基本的测试.但有时需要更复杂的测试场景,所以还有更多其他的元素.清看下表,了解各种单元组的用途. 可添加的单元组 用途 Sa ...
- Eureka 系列(03)Spring Cloud 自动装配原理
Eureka 系列(03)Spring Cloud 自动装配原理 [TOC] 0. Spring Cloud 系列目录 - Eureka 篇 本文主要是分析 Spring Cloud 是如何整合 Eu ...