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】993. Cousins in Binary Tree
题目如下: In a binary tree, the root node is at depth 0, and children of each depth k node are at depth ...
- Python--面向对象的程序设计之组合应用、开发软件规范
组合应用: class Teacher: def __init__(self,name,age,sex,salary,level): self.name=name self.age=age self. ...
- 内核设备模型从kobject到子系统
内核设备模型 目的:表示设备和设备在系统中的拓扑关系 优点:1减少内核代码量,2可以统一查看所有设备状态和所连接的总线,3可以 ...
- hdu 3974 Assign the task (线段树+树的遍历)
Description There is a company that has N employees(numbered from 1 to N),every employee in the comp ...
- webpack+vue+koa+mongoDB,从零开始搭建一个网站
github 地址 https://github.com/wangxiaoxi... webpakc+vue的搭建1.新建项目文件夹(see-films);2.npm init //初始化项目3.搭建 ...
- PHP浮点计算结果返回异常问题
php中如果直接小数点进行计算的话.比如16.8*3var_dump是50.4.但是return就变成了50.400000000000006.至于是什么原因本人尚不得而知.解决方法是用把计算放入下面的 ...
- ORACLE切非归档模式:
C:\Documents and Settings\Administrator>sqlplus /nologSQL> conn / as sysdbaConnected to an idl ...
- send_keys报错element not interactable
这两天要在阿里云日志中操作UI,以输入关键字搜索日志. 在send_keys时报错element not interactable. iframe 第一个问题是iframe,通过切换iframe解决: ...
- 第一周复习二 (CSS样式表及其属性)
样式表三种写法 1内联写法:style直接写在标签内.个人感觉多用于个别标签,一般情况优先级较高 style="font-size:16px;" 2内嵌写法:写在<head& ...
- Qt 打开指定网站/系统文件夹
本文转载自:http://blog.csdn.net/robertkun/article/details/7802977和http://hi.baidu.com/xyhouse/item/ccf ...