D A Y 16 DAY 16 DAY16
呃呃,最近几天沉迷于做题,不是很想打博客,不过呢,还是得敷衍敷衍。
T 1 T1 T1
额,十分不友好,第一题就直接给出一道奇奇怪怪的dp,我直接连暴力都不会打了,惨淡爆零。不过正解确实挺难的,自己理解了老半天才自己推了出来,推理过程呢因为我懒,自行脑补。AC code:
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
const ll inf = 1e18;
const int N = 3e5 + 10;
struct Node{
int to,next,val;
} f[N << 1];
int T,col[N],n,q[N],l,r,head[N],cnt,fa[N];
ll g[N][3];
int read()
{
int x = 0,w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') w = -1;ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}
return x * w;
}
void add(int u,int v,int w)
{
f[++ cnt].to = v;
f[cnt].val = w;
f[cnt].next = head[u];
head[u] = cnt;
}
void bfs()
{
l = 0,r = 1;
fa[1] = -1;
q[1] = 1;
while (l < r)
{
int u = q[++ l];
for (int i = head[u],v; i; i = f[i].next)
{
v = f[i].to;
if (v == fa[u]) continue;
fa[v] = u;
q[++ r] = v;
}
}
}
ll min(ll a,ll b) {return a < b ? a : b;}
ll solve()
{
for (int l = n,u; l >= 1; l --)
{
u = q[l];
if (col[u] == 0)
{
g[u][0] = inf;
g[u][1] = 0;
g[u][2] = inf;
for (int i = head[u],v; i; i = f[i].next)
{
v = f[i].to;
if (v == fa[u]) continue;
g[u][1] += min(g[v][0] + 1ll * f[i].val,min(g[v][1],g[v][2] + 1ll * f[i].val));
}
for (int i = head[u],v; i; i = f[i].next)
{
v = f[i].to;
if (v == fa[u]) continue;
g[u][2] = min(g[u][2],g[v][2] + g[u][1] - min(g[v][0] + 1ll * f[i].val,min(g[v][1],g[v][2] + 1ll * f[i].val)));
}
} else if (col[u] == 1)
{
g[u][0] = 0;
g[u][1] = inf;
g[u][2] = 0;
for (int i = head[u],v; i; i = f[i].next)
{
v = f[i].to;
if (v == fa[u]) continue;
g[u][0] += min(g[v][0],min(g[v][1] + 1ll * f[i].val,g[v][2] + 1ll * f[i].val));
g[u][2] += min(g[v][0] + f[i].val,min(g[v][1],g[v][2] + 1ll * f[i].val));
}
} else
{
g[u][0] = 0;
g[u][1] = 0;
g[u][2] = inf;
for (int i = head[u],v; i; i = f[i].next)
{
v = f[i].to;
if (v == fa[u]) continue;
g[u][0] += min(g[v][0],min(g[v][1] + 1ll * f[i].val,g[v][2] + 1ll * f[i].val));
g[u][1] += min(g[v][0] + 1ll * f[i].val,min(g[v][1],g[v][2] + 1ll * f[i].val));
}
for (int i = head[u],v; i; i = f[i].next)
{
v = f[i].to;
if (v == fa[u]) continue;
g[u][2] = min(g[u][2],g[v][2] + g[u][1] - min(g[u][2],min(g[v][0] + 1ll * f[i].val,min(g[v][1],g[v][2] + 1ll * f[i].val))));
}
}
}
return min(g[1][0],min(g[1][1],g[1][2]));
}
int main()
{
T = read();
while (T --)
{
memset(head,0,sizeof head);
cnt = 0;
n = read();
for (int i = 1; i <= n; i ++) col[i] = read();
for (int i = 1,u,v,w; i < n; i ++)
u = read(),v = read(),w = read(),add(u,v,w),add(v,u,w);
bfs();
printf("%lld\n",solve());
}
return 0;
}
码量真是非常的大。
T 2 T2 T2
这题又是十分的不友好,正解是最小割。题目很猥琐,竟然要你判断方法是否为一,着实烧脑,同时也大大加大了码量,不过呢我理解了最小割等于最大流这个定理还是不错的。
#include <cstdio>
#include <cstring>
#include <queue>
#define ll long long
using namespace std;
const int inf = 1e9 + 10;
const int M = 4e4 + 10;
const int N = 4100;
struct Edge{
int to,next,val;
} f[M << 1];
struct Node{
int to,next,flow;
} t[M << 1];
int T,n,m,cnt,tot = 0,a[N],dep[N],bl[N],head[N],head1[N];
bool vis[N];
ll dis[2][N];
int min(int a,int b) {return a < b ? a : b;}
int read()
{
int x = 0,w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') w = -1;ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0';ch = getchar();}
return x * w;
}
void add(int u,int v,int w)
{
f[++ cnt].to = v;
f[cnt].val = w;
f[cnt].next = head[u];
head[u] = cnt;
}
void link(int u,int v,int w)
{
t[++ cnt].to = v;
t[cnt].flow = w;
t[cnt].next = head1[u];
head1[u] = cnt;
t[++ cnt].to = u;
t[cnt].flow = 0;
t[cnt].next = head1[v];
head1[v] = cnt;
}
void dij(int op,int x)
{
memset(vis,0,sizeof vis);
memset(dis[op],0x7f,sizeof dis[op]);
dis[op][x] = 0;
for (int l = 1; l <= n; l ++)
{
int u = 0;
for (int j = 1; j <= n; j ++)
if (!vis[j] && dis[op][j] < dis[op][u]) u = j;
vis[u] = 1;
for (int i = head[u],v; i; i = f[i].next)
if (dis[op][f[i].to] > dis[op][u] + 1ll * f[i].val) dis[op][f[i].to] = dis[op][u] + 1ll * f[i].val;
}
}
queue <int> q;
bool bfs()
{
memset(dep,-1,sizeof dep);
q.push(1);
dep[1] = 1;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head1[u],v; i; i = t[i].next)
{
v = t[i].to;
if (!t[i].flow || ~dep[v]) continue;
dep[v] = dep[u] + 1;
q.push(v);
}
}
return ~dep[n];
}
int dinic(int x,int lim)
{
if (!lim || x == n) return lim;
int flow = 0;
for (int i = head1[x],v; i; i = t[i].next)
{
v = t[i].to;
if (dep[v] != dep[x] + 1 || !t[i].flow) continue;
int mi = dinic(v,min(lim,t[i].flow));
if (mi)
{
lim -= mi;
flow += mi;
t[i].flow -= mi;
t[i ^ 1].flow += mi;
if (!lim) break;
}
}
return flow;
}
void dfs1(int now)
{
if (bl[now]) return;
bl[now] = 1;
for (int i = head1[now]; i; i = t[i].next)
if (t[i].flow) dfs1(t[i].to);
}
void dfs2(int now){
if (bl[now]) return;
bl[now] = 2;
for (int i = head1[now]; i; i = t[i].next)
if (t[i ^ 1].flow) dfs2(t[i].to);
}
int main()
{
T = read();
while (T --)
{
memset(head,0,sizeof head);
memset(bl,0,sizeof bl);
cnt = 0;
n = read(),m = read();
for (int i = 1; i < n; i ++) a[i] = read();
a[n] = inf;
for (int i = 1,u,v,w; i <= m; i ++)
u = read(),v = read(),w = read(),add(u,v,w),add(v,u,w);
cnt = 1;
dij(0,1);
dij(1,n);
tot = n;
memset(head1,0,sizeof head1);
for (int u = 1; u < n; u ++)
for (int i = head[u]; i; i = f[i].next)
if (u != f[i].to && dis[0][u] + dis[1][f[i].to] + f[i].val == dis[0][n])
tot ++,link(u,tot,a[u]),link(tot,f[i].to,a[f[i].to]);
int ans1 = 0,ans2 = 0;
while (bfs()) ans1 += dinic(1,inf);
dfs1(1);
dfs2(n);
for (int u = 1; u <= tot; u ++)
for (int i = head1[u]; i; i = t[i].next)
if (bl[u] && bl[t[i].to] && bl[u] != bl[t[i].to]) ans2 += t[i].flow;
if (ans1 == ans2) printf("Yes %d\n",ans1); else printf("No %d\n",ans1);
}
return 0;
}
T 3 T3 T3
考场的时候真的毫无思绪,不过正解是主席树感觉还行,不错地温习了这个算法。
#include<cstdio>
#include<algorithm>
#define MN 201000
using namespace std;
struct tnode{
int w,l,r,ls,rs;
}t[MN<<5];
int n,m,x,y,k,a[MN],b[MN],root[MN],q,w,r[6],l[6],qnum,cnt;
int build(int l,int r)
{
int k=++cnt;
t[k].l=l,t[k].r=r;
if (l==r) return k;
int mid=(l+r)>>1;
t[k].ls=build(l,mid);
t[k].rs=build(mid+1,r);
return k;
}
int addt(int k,int z)
{
int nb=++cnt;
t[nb]=t[k];t[nb].w++;
if (t[k].l==z&&t[k].r==z) return nb;
int mid=(t[k].l+t[k].r)>>1;
if (z<=mid) t[nb].ls=addt(t[k].ls,z);
else t[nb].rs=addt(t[k].rs,z);
return nb;
}
int query(int k)
{
if (t[r[1]].l==t[r[1]].r) return t[r[1]].l;
int num=0;
for(int i=1;i<=qnum;i++)
num+=t[t[r[i]].ls].w-t[t[l[i]].ls].w;
if(k<=num){
for(int i=1;i<=qnum;i++)
r[i]=t[r[i]].ls,l[i]=t[l[i]].ls;
return query(k);
}
else{
for(int i=1;i<=qnum;i++)
r[i]=t[r[i]].rs,l[i]=t[l[i]].rs;
return query(k-num);
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n);
int q=unique(b+1,b+1+n)-b-1;
root[0]=build(1,q);
for (int i=1;i<=n;i++)
{
int te=lower_bound(b+1,b+1+q,a[i])-b;
root[i]=addt(root[i-1],te);
}
for (int i=1;i<=m;i++)
{
scanf("%d%d",&qnum,&k);
for(int j=1;j<=qnum;j++)
scanf("%d%d",&l[j],&r[j]),l[j]=root[l[j]-1],r[j]=root[r[j]];
printf("%d\n",b[query(k)]);
}
}
合计7400+bytes,真的是一套真真正正的码农题,我不中意。
0 + 0 + 20 = 20,惨淡爆20.。。。。