NOIP模拟测试29(A)

半城伤御伤魂 提交于 2019-11-28 06:21:06

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:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<queue>
 4 using namespace std;
 5 const int N=1010;
 6 const int M=20010;
 7 const int inf=1e9+10;
 8 int n,m,k,s,nm=1,ans=0;
 9 int fi[N],p[N],d[N];
10 bool v[N];
11 struct edge{
12     int v,ne;
13     int l,a,b;
14 }e[M+N<<1];
15 queue<int> q;
16 int read()
17 {
18     int s=0;char c=getchar();
19     while(c<'0'||c>'9') c=getchar();
20     while(c>='0'&&c<='9'){
21         s=(s<<3)+(s<<1)+c-'0';
22         c=getchar();
23     }
24     return s;
25 }
26 void add(int x,int y,int z1,int z2,int z3)
27 {
28     e[++nm].v=y;e[nm].a=z1;e[nm].b=z1+z2;
29     e[nm].l=z3;e[nm].ne=fi[x];fi[x]=nm;
30     e[++nm].v=x;e[nm].a=-z1;e[nm].b=-z2;
31     e[nm].l=0;e[nm].ne=fi[y];fi[y]=nm;
32 }
33 bool spfa()
34 {
35     for(int i=1;i<=n;i++){
36         p[i]=0;d[i]=inf;v[i]=false;
37     }
38     while(!q.empty()) q.pop();
39     d[1]=0;v[1]=true;q.push(1);
40     while(!q.empty()){
41         int x=q.front();q.pop();
42         v[x]=false;
43         for(int i=fi[x];i!=0;i=e[i].ne){
44             int y=e[i].v;
45             if(e[i].l==0) continue;
46             if(d[y]>d[x]+e[i].b){
47                 d[y]=d[x]+e[i].b;p[y]=i;
48                 if(!v[y]){
49                     v[y]=true;q.push(y);
50                 }
51             }
52         }
53     }
54     if(d[n]<inf) return true;
55     else return false;
56 }
57 void update()
58 {
59     int x=n;ans+=d[n];
60     while(x!=1){
61         int y=p[x];
62         if((y&1)==0) e[y].b+=e[y].a,e[y^1].b+=e[y^1].a;
63         else e[y].b-=e[y].a,e[y^1].b-=e[y^1].a;
64         e[y].l-=1;e[y^1].l+=1;
65         x=e[y^1].v;
66     }
67 }
68 int main()
69 {
70     scanf("%d%d%d%d",&n,&m,&k,&s);
71     n++;
72     for(int i=1;i<=s;i++){
73         int x=read();
74         add(x,n,0,0,inf);
75     }
76     for(int i=1;i<=m;i++){
77         int x=read(),y=read(),a=read(),b=read(),c=read();
78         add(x,y,a,b,c);
79     }
80     int tot=0;
81     while(tot<k&&spfa()){
82         update();tot++;
83     }
84     if(tot!=k) printf("-1\n");
85     else printf("%d\n",ans);
86     return 0;
87 }
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:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<string>
  4 #include<cstring>
  5 #include<queue>
  6 #define LL long long
  7 using namespace std;
  8 const LL mod=1e9+7;
  9 int n,k,rt=0,cnt=0;
 10 string s;
 11 int a[2][510];
 12 LL dp[510][210][20][4];
 13 bool v[510][210][20][4];
 14 struct trie{
 15     int ch[10],fail;
 16     int e;
 17 }t[210];
 18 queue<int> q,q1,q2,q3,q4;
 19 void insert()
 20 {
 21     int now=rt;
 22     for(int i=0;i<s.size();i++){
 23         int x=s[i]-'0';
 24         if(t[now].ch[x]==0)
 25             t[now].ch[x]=++cnt;
 26         now=t[now].ch[x];
 27     }
 28     t[now].e++;
 29 }
 30 void build()
 31 {
 32     for(int i=0;i<=9;i++){
 33         if(t[rt].ch[i]!=0) q.push(t[rt].ch[i]);
 34     }
 35     while(!q.empty()){
 36         int x=q.front();q.pop();
 37         for(int i=0;i<=9;i++){
 38             if(t[x].ch[i]!=0){
 39                 t[t[x].ch[i]].fail=t[t[x].fail].ch[i];
 40                 t[t[x].ch[i]].e+=t[t[t[x].fail].ch[i]].e;
 41                 q.push(t[x].ch[i]);
 42             }
 43             else t[x].ch[i]=t[t[x].fail].ch[i];
 44         }
 45     }
 46 }
 47 LL work(int id)
 48 {    
 49     memset(dp,0,sizeof(dp));
 50     memset(v,false,sizeof(v));
 51     while(!q1.empty()){
 52         q1.pop();q2.pop();q3.pop();q4.pop();
 53     }
 54     dp[0][rt][0][3]=1;v[0][rt][0][3]=true;
 55     q1.push(0);q2.push(rt);q3.push(0);q4.push(3);
 56     while(!q1.empty()){
 57         int x=q1.front(),y=q2.front(),z=q3.front(),op=q4.front();
 58         v[x][y][z][op]=false;
 59         q1.pop();q2.pop();q3.pop();q4.pop();
 60         if(x==a[id][0]) break;
 61         for(int i=0;i<=((op&1)==1?a[id][x+1]:9);i++){
 62             int yy=t[y].ch[i];int zz=z+t[yy].e;
 63             if(zz>k) zz=k;
 64             if((op&2)==2&&i==0){
 65                 if((op&1)==1&&i==a[id][x+1]){
 66                     dp[x+1][yy][zz][3]=(dp[x+1][yy][zz][3]+dp[x][y][z][op])%mod;
 67                     if(!v[x+1][yy][zz][3]){
 68                         q1.push(x+1);q2.push(yy);q3.push(zz);q4.push(3);
 69                         v[x+1][yy][zz][3]=true;
 70                     }
 71                 }
 72                 else{
 73                     dp[x+1][yy][zz][2]=(dp[x+1][yy][zz][2]+dp[x][y][z][op])%mod;
 74                     if(!v[x+1][yy][zz][2]){
 75                         q1.push(x+1);q2.push(yy);q3.push(zz);q4.push(2);
 76                         v[x+1][yy][zz][2]=true;
 77                     }
 78                 }
 79             }
 80             else{
 81                 if((op&1)==1&&i==a[id][x+1]){
 82                     dp[x+1][yy][zz][1]=(dp[x+1][yy][zz][1]+dp[x][y][z][op])%mod;
 83                     if(!v[x+1][yy][zz][1]){
 84                         q1.push(x+1);q2.push(yy);q3.push(zz);q4.push(1);
 85                         v[x+1][yy][zz][1]=true;
 86                     }
 87                 }
 88                 else{
 89                     dp[x+1][yy][zz][0]=(dp[x+1][yy][zz][0]+dp[x][y][z][op])%mod;
 90                     if(!v[x+1][yy][zz][0]){
 91                         q1.push(x+1);q2.push(yy);q3.push(zz);q4.push(0);
 92                         v[x+1][yy][zz][0]=true;
 93                     }
 94                 }
 95             }
 96         }
 97     }
 98     LL ans=0;
 99     for(int j=0;j<=cnt;j++){
100         ans=(ans+dp[a[id][0]][j][k][0])%mod;
101         ans=(ans+dp[a[id][0]][j][k][1])%mod;
102     }
103     return ans;
104 }
105 int main()
106 {
107     scanf("%d%d",&n,&k);
108     cin>>s;a[0][0]=s.size();
109     for(int i=1;i<=a[0][0];i++) a[0][i]=s[i-1]-'0';
110     cin>>s;a[1][0]=s.size();
111     for(int i=1;i<=a[1][0];i++) a[1][i]=s[i-1]-'0';
112     for(int i=1;i<=n;i++){
113         cin>>s;insert();
114     }
115     build();
116     LL ans=work(1);
117     ans-=work(0);
118     ans=(ans%mod+mod)%mod;
119     printf("%lld\n",ans);
120     return 0;
121 }
T2

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!