csp-s模拟4

A. 商品

可以发现,选取的 \(l,r\) 一定有一个边界是原序列的数,所以我们 \(O(n)\) 枚举 \(l/r\) ,考虑如何快速的求出临项差的

绝对值,我们可以把相邻两个数大的放到一个数组,小的放到一个数组,先排序,每次枚举的 \(l,r\) 二分查找在数组中的

位置,贡献就是 \(l\) 左边的数个数 * \(l\)+\(r\) 右边的数个数 * \(r\)+ \(l,r\) 中间的数的和,前两项 \(O(1)\) 算,后一项前缀和优化一下

总复杂度 \(O(nlogn)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
const int maxn=2e5+10;
using namespace std;
int a[maxn],q[maxn],d,top,n,da[maxn],xi[maxn],ans,sum1[maxn],sum2[maxn],s,t;

signed main()
{
	freopen("goods.in","r",stdin);
	freopen("goods.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>d;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=2;i<=n;i++)
	{
		da[i-1]=max(a[i-1],a[i]);
		xi[i-1]=min(a[i-1],a[i]);
	}
	sort(da+1,da+n);sort(xi+1,xi+n);
	for(int i=1;i<=n;i++)
	{
		if(a[i]!=a[i-1])q[++top]=a[i];
	}
	n--;
	for(int i=1;i<=n;i++)
	{
		sum1[i]=sum1[i-1]+da[i];
		sum2[i]=sum2[i-1]+xi[i];
	}
	for(int i=1;i<=top;i++)
	{
		int l=q[i],r=l+d,minn=0,maxx=0;
		s=lower_bound(da+1,da+1+n,l)-da;
		t=lower_bound(da+1,da+1+n,r+1)-da;
		maxx=(s-1)*l+sum1[t-1]-sum1[s-1]+(n-t+1)*r;
		s=lower_bound(xi+1,xi+1+n,l)-xi;
		t=lower_bound(xi+1,xi+1+n,r+1)-xi;
		minn=(s-1)*l+sum2[t-1]-sum2[s-1]+(n-t+1)*r;
		ans=max(ans,maxx-minn);
	}
	for(int i=1;i<=top;i++)
	{
		int r=q[i],l=r-d,minn=0,maxx=0;
		s=lower_bound(da+1,da+1+n,l)-da;
		t=lower_bound(da+1,da+1+n,r+1)-da;
		maxx=(s-1)*l+sum1[t-1]-sum1[s-1]+(n-t+1)*r;
		s=lower_bound(xi+1,xi+1+n,l)-xi;
		t=lower_bound(xi+1,xi+1+n,r+1)-xi;
		minn=(s-1)*l+sum2[t-1]-sum2[s-1]+(n-t+1)*r;
		ans=max(ans,maxx-minn);
	}
	cout<<ans<<'\n';

	return 0;
}
/*
8 3
3 1 4 1 5 9 2 6

*/

B. 价值

感谢5k和wps在这道题对我的贡献

考虑树形 \(dp\)\(f_{u,i,j,k}\) 表示 \(u\) 的子树中,\(u\) 是否匹配,最左的叶子节点是否匹配,最右的叶子节点是否匹配。

\(dp\) 时就一个个合并子树,用合并前的整个树加上这个子树去更新合并后的整个树,分讨很多,看代码吧。

边界:\(f_{u,0,0,0}=1\),如果 \(u\) 是叶子节点,则 \(f_{u,1,0,1}=f_{u,1,1,0}=1\)(就是叶子节点向右/左匹配时自己也同时匹配)

点击查看代码
#include<bits/stdc++.h>
#define int long long
const int mod=998244353;
const int maxn=2e5+10;
using namespace std;
int head[maxn],to[maxn],nxt[maxn],tot,ans;
int n,f[maxn][2][2][2];

void add(int x,int y)
{
	to[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
int mo(int x)
{
//	cout<<x<<endl; 
	return x>=mod?x%mod:x;
} 
void lsx(int x)
{
	f[x][0][0][0]=1;
	int a[2][2][2];
	for(int i=head[x];i;i=nxt[i])
	{
		int y=to[i];
		lsx(y); 
		if(i==head[x])
		{
			f[x][1][1][1]=f[y][0][1][1];
			f[x][1][0][0]=f[y][0][0][0];
			f[x][1][1][0]=f[y][0][1][0];
			f[x][1][0][1]=f[y][0][0][1];
			f[x][0][1][1]=mo(f[y][0][1][1]+f[y][1][1][1]);
			f[x][0][1][0]=mo(f[y][0][1][0]+f[y][1][1][0]);
			f[x][0][0][1]=mo(f[y][0][0][1]+f[y][1][0][1]);
			f[x][0][0][0]=mo(f[y][0][0][0]+f[y][1][0][0]);
		}
		else
		{
			for(int j=0;j<=1;j++)for(int k=0;k<=1;k++)for(int s=0;s<=1;s++) a[j][k][s]=f[x][j][k][s];
			f[x][1][1][1]=mo(mo(a[1][1][1]*mo(f[y][1][1][1]+f[y][0][1][1]))+mo(a[0][1][1]*f[y][0][1][1]))+mo(mo(a[1][1][0]*mo(f[y][1][0][1]+f[y][0][0][1]))+mo(a[0][1][0]*f[y][0][0][1]));
			f[x][1][1][0]=mo(mo(a[1][1][1]*mo(f[y][1][1][0]+f[y][0][1][0]))+mo(a[0][1][1]*f[y][0][1][0]))+mo(mo(a[1][1][0]*mo(f[y][1][0][0]+f[y][0][0][0]))+mo(a[0][1][0]*f[y][0][0][0]));
			f[x][1][0][1]=mo(mo(a[1][0][1]*mo(f[y][1][1][1]+f[y][0][1][1]))+mo(a[0][0][1]*f[y][0][1][1]))+mo(mo(a[1][0][0]*mo(f[y][1][0][1]+f[y][0][0][1]))+mo(a[0][0][0]*f[y][0][0][1]));
			f[x][1][0][0]=mo(mo(a[1][0][1]*mo(f[y][1][1][0]+f[y][0][1][0]))+mo(a[0][0][1]*f[y][0][1][0]))+mo(mo(a[1][0][0]*mo(f[y][1][0][0]+f[y][0][0][0]))+mo(a[0][0][0]*f[y][0][0][0]));
			f[x][0][1][1]=mo(mo(a[0][1][1]*mo(f[y][0][1][1]+f[y][1][1][1]))+mo(a[0][1][0]*mo(f[y][0][0][1]+f[y][1][0][1])));
			f[x][0][1][0]=mo(mo(a[0][1][1]*mo(f[y][0][1][0]+f[y][1][1][0]))+mo(a[0][1][0]*mo(f[y][0][0][0]+f[y][1][0][0])));
			f[x][0][0][1]=mo(mo(a[0][0][1]*mo(f[y][0][1][1]+f[y][1][1][1]))+mo(a[0][0][0]*mo(f[y][0][0][1]+f[y][1][0][1])));
			f[x][0][0][0]=mo(mo(a[0][0][1]*mo(f[y][0][1][0]+f[y][1][1][0]))+mo(a[0][0][0]*mo(f[y][0][0][0]+f[y][1][0][0])));
		}	
	}
	if(!head[x]) f[x][1][1][0]=f[x][1][0][1]=1;
}

signed main()
{
	freopen("value.in","r",stdin);
	freopen("value.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
	cin>>n;
	for(int i=2;i<=n;i++)
	{
		int x;
		cin>>x;
		add(x,i);
	}
	lsx(1);
	ans=mo(mo(f[1][1][0][0]+f[1][1][1][1])+mo(f[1][0][0][0]+f[1][0][1][1]));
	cout<<ans;

	return 0;
}
/*
18
1 2 3 4 5 6 4 3 2 2 11 2 13 2 2 1 1

*/

C. 货币

不枉我寒假学了整7天的网络流,经5k一点就会了,也是下午来了很快就 \(A\)

考虑横着一张 \(2*n\) 的图,上下两条 \((1,i)->(1,i+1),(2,i)->(2,i+1)\) 显然这两条边只能同时走一条

没限制时直接裸的最小割就行了,考虑加上限制应该如何割边

image

\(v1,v2\) 分别表示\((1,i)->(1,i+1),(2,i)->(2,i+1)\) 的边权,我们想让割这两个红叉的边时,多付出代价,只需要

像上图一样,连一条边,使得图又联通导致必须多割一条边或换别的边割,

\((1,i)->(2,i)/(2,i)->(1,i)\) 的这种连接两条路的边可以发现和限制边是等价的,按上面方法连即可

对于第一条和最后一条链接上下两条路的边,可以直接把第一条边边权加到第二条路的第一条横向边,把最后一条边边权加到

第一条路的最后一条横向边即可,没必要新建两个竖边

点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e7+5;
const int INF=0x7f7f7f7f;
int n,s,t,p,h,r,cnt,now,w,sum,d[maxn>>4],b[maxn>>4],c[maxn>>4];
int head[maxn<<1],tot=1;
struct node
{
    int to,nxt,flow,dis;
}m[maxn<<1];
void add(int x,int y,int z)
{
    m[++tot].to=y;
    m[tot].nxt=head[x];
    m[tot].dis=z;
    head[x]=tot;
    m[tot].flow=0;
}
void addm(int x,int y,int z)
{
    add(x,y,z);add(y,x,0);
}
int deep[maxn],a[maxn];
queue<int>q;
bool bfs()
{
    for(int i=1;i<=t;i++)deep[i]=0;
    deep[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        a[u]=head[u];
        for(int i=head[u];i;i=m[i].nxt)
        {
            if(!deep[m[i].to]&&m[i].dis>m[i].flow)
            {
                deep[m[i].to]=deep[u]+1;
                q.push(m[i].to);
            }
        }
    }
    return deep[t];
}
int dfs(int now,int fa1)
{
    if(now==t||!fa1)return fa1;
    int fa=0,d;
    for(int i=a[now];i;i=m[i].nxt)
    {   
        a[now]=i;
        if(deep[m[i].to]==deep[now]+1&&(d=dfs(m[i].to,min(fa1-fa,m[i].dis-m[i].flow))))
        {
            m[i].flow+=d;
            m[i^1].flow-=d;
            fa+=d;
            if(fa==fa1) break;
        }
    }
    return fa;
}
void dinic()
{
    int res=0;
    while(bfs())
    {
        res+=dfs(0,INF);
    }
    cout<<res<<'\n';
}
signed main()
{	
	freopen("currency.in","r",stdin);
	freopen("currency.out","w",stdout);
    ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>p;
	s=0,t=n+1;
	for(int i=1;i<n;i++)
		cin>>d[i];
	for(int i=1;i<=n;i++)
		cin>>b[i];
	for(int i=1;i<n;i++)
		cin>>c[i];
	c[1]+=b[1];d[n-1]+=b[n];
	for(int i=1;i<n;i++)
		addm(s,i,d[i]);
	for(int i=2;i<n;i++)
		addm(i,i-1,b[i]),addm(i-1,i,b[i]);
	for(int i=1;i<n;i++)
		addm(i,t,c[i]);
	for(int i=1;i<=p;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		addm(y,x,z);
	}
    dinic();

    return 0;
}
posted @ 2024-09-24 21:42  _君の名は  阅读(26)  评论(0编辑  收藏  举报