2019.7.10 JZ DAY16总结

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.。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值