周赛作业, Underfail(费用流)
题意是给你一个字符串,每个位置最多只能match k次,然后给你一些字符串,每个字符串有一些权值,每次可以匹配一个子段,匹配完之后子段使用次数 - 1, 分数 += wi
问满足条件下的最大权值
这个问题让我想起来了HDU的某题,好像20年的时候写过,就是区间最大覆盖问题,然后套板子,t了,不懂,遂去查题解
发现图是长这个样子
所以需要加的边是l -> R + 1,要不然会出现负环,就会g
那就改变连边,然后字符串匹配可以用字符串hash加速到O(n)
就可以了
AC代码:
#include <bits/stdc++.h> using namespace std; constexpr int limit = (100000 + 5);//防止溢出 #define INF 0x3f3f3f3f #define inf 0x3f3f3f3f3f #define lowbit(i) i&(-i)//一步两步 #define EPS 1e-9 #define FASTIO ios::sync_with_stdio(false);cin.tie(0),cout.tie(0); #define ff(a) printf("%d\n",a ); #define pi(a, b) pair<a,b> #define rep(i, a, b) for(ll i = a; i <= b ; ++i) #define per(i, a, b) for(ll i = b ; i >= a ; --i) #define MOD 998244353 #define traverse(u) for(int i = head[u]; ~i ; i = edge[i].next) #define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\data.txt", "rt", stdin) #define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\akioi\\dabiao.txt", "wt", stdout) typedef long long ll; typedef unsigned long long ull; char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf; inline ll read() { #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) ll sign = 1, x = 0; char s = getchar(); while (s > '9' || s < '0') { if (s == '-')sign = -1; s = getchar(); } while (s >= '0' && s <= '9') { ll x = (x << 3) + (x << 1) + s - '0'; s = getchar(); } return x * sign; #undef getchar }//快读 void print(ll x) { if (x / 10) print(x / 10); *O++ = x % 10 + '0'; } void write(ll x, char c = 't') { if (x < 0)putchar('-'), x = -x; print(x); if (!isalpha(c))*O++ = c; fwrite(obuf, O - obuf, 1, stdout); O = obuf; } int n, m, k,vs,ve; int head[limit],cnt; int dist[limit],fa[limit],vis[limit],pre[limit]; struct node{ int to, next, flow, w; }edge[limit<<1]; void add_one(int u, int v, int flow, int w){ edge[cnt].to = v; edge[cnt].flow = flow; edge[cnt].w = w; edge[cnt].next = head[u]; head[u] = cnt++; } void add(int u, int v, int flow ,int w){ add_one(u,v,flow,w); add_one(v,u,0,-w); } void init(int flag = 0){ if(flag){ memset(dist, INF, sizeof(dist)); memset(vis, 0 , sizeof(vis)); }else{ memset(head, -1, sizeof(head)); cnt = 0; } } int spfa(){ queue<int>q; init(1); dist[vs] = 0; vis[vs] = 1; q.push(vs); pre[ve] = -1; while (q.size()){ int u = q.front(); q.pop(); vis[u] = 0; for(int i = head[u]; ~i; i = edge[i].next){ int v = edge[i].to, w = edge[i].w; int stream = edge[i].flow; if(dist[u] + w < dist[v] && stream > 0){ dist[v] = dist[u] + w; pre[v] = i; fa[v] = u; if(!vis[v]){ vis[v] = 1; q.push(v); } } } } return ~pre[ve]; } int max_flow,min_cost; void dinic(){ while (spfa()){ int min_flow = INF; for(int i = ve; i != vs; i = fa[i]){ min_flow = min(min_flow, edge[pre[i]].flow); } max_flow += min_flow; min_cost += dist[ve] * min_flow; for(int i = ve; i != vs; i = fa[i]){ edge[pre[i]].flow -= min_flow; edge[pre[i] ^ 1].flow += min_flow; } } } struct hasher{ ll hash[limit]; ll p[limit]; void init(string & str){ p[0] = 1; for(int i = 1; i <= n; ++i){ p[i] = p[i - 1] * 26; hash[i] = hash[i - 1] * 26 + str[i]; } } ll get(int l, int r){ return hash[r] - hash[l - 1] * p[r - l + 1]; } ll calc(string & str){ ll ans = 0; for(auto && it : str){ ans = ans * 26 + it; } return ans; } }; int a[limit]; int l[limit], r[limit]; int c[limit]; int rev[limit]; void solve(){ init(); cin>>n; string str; cin>>str; str = " " + str; vs = 80001, ve = vs + 1; int tot = 0; int tot1 = 0; hasher h; h.init(str); cin>>k; rep(i,1,k){ string s; ll w; cin>>s>>w; ll val = h.calc(s); rep(hh,1, n){ //暴力匹配 if(hh + s.length() - 1 > n)break; if(h.get(hh, hh + s.length() - 1) == val){ a[++tot1] = hh; a[++tot1] = hh + s.length(); l[++tot] = hh; r[tot] = hh + s.length(); c[tot] = w; } } } cin>>k; sort(a + 1, a + 1 + tot1); tot1 = unique(a + 1, a + 1 + tot1) - a - 1; rep(i,1,tot1){ rev[a[i]] = i; //反射 } rep(i,1,tot1){ add(i, i + 1, k, 0); } add(vs, 1, k, 0); add(tot1 + 1, ve, k, 0); rep(i,1,tot){ add(rev[l[i]], rev[r[i]], 1, -c[i]); } dinic(); cout<<-min_cost<<endl; }; int32_t main() { #ifdef LOCAL FOPEN; // FOUT; #endif FASTIO // int kase; // cin>>kase; // while (kase--) solve(); cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << "s\n"; return 0; }
天才选手zerol的主页:https://zerol.me/
|
WeepingDemon的个人主页:https://weepingdemon.gitee.io/blog/