123789456ye

已AFO

11.2考试总结

2019.11.2 CSP模拟赛

T1 高斯消元

与标题没有任何关系
题意:\(n\)个块,重复\(m\)次,每个块有颜色\(a_{i}\),如果连续颜色相同的块数\(\ge k\),则删去\(k\)块。求最后剩多少块。\(n\leq 10^5,m,k\leq 10^9\)
题解:拿两个指针把前后的处理好,如果有剩的块则直接出答案。否则看代码吧
复杂度:\(O(n)\)

#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
long long ans,tp,cnt,s[maxn][2],n,m,k,tot;

int main()
{
	freopen("guass.in","r",stdin),freopen("guass.out","w",stdout);
	scanf("%lld%lld%lld",&n,&m,&k);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&tp);
		if(!cnt||s[cnt][0]!=tp)
		{
			s[++cnt][0]=tp;
			s[cnt][1]=1;
		}
		else ++s[cnt][1];
		if(s[cnt][1]==k) s[cnt--][1]=0;
	}
	for(int i=1;i<=cnt;++i) tot+=s[i][1];
	int head=1,tail=cnt;
	while(head<tail&&s[head][0]==s[tail][0])
	{
		if((s[head][1]+s[tail][1])%k==0) ++head,--tail;
		else
		{
			s[head][1]=(s[head][1]+s[tail][1])%k;
			s[tail][1]=0;
			break;
		}
	}
	if(head<tail)
	{
		for(int i=head;i<=tail;++i) ans+=s[i][1];
		ans*=(m-1);
		ans+=tot;//m个剩余段+开始时的减去剩余段
	}
	else if(head==tail)
	{
		if(s[head][1]*m%k==0) ans=0;
		else ans=tot-s[head][1]+s[head][1]*m%k;
		//开始时的段减去开头加上开头m遍后的剩余段
	}
	printf("%lld\n",ans);
	return 0;
}

T2 糖果镇

题意:\(m×n\)的网格,只能往下或往右走,走过每一点都有获得权值,求从\((1,1)\to(m,n)\)的模\(p\)意义下最大值。\(m\leq 3,n\leq 10^5\)
题解:\(m\leq 2\)时显然前缀和即可。
\(m==3\)时,\(ans=s_{1,i}+s_{2,j}-s_{2,i-1}+s_{3,n}-s_{3,j-1}\)
所以枚举第二三行分界点\(j\),将之前的\(i\)扔到\(set\)里,求\(max(?<(p-(sum_{1,i}-sum_{2,i-1})))\)
复杂度:\(n\log n\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
set<ll> se;
set<ll>::iterator it;
ll sum[4][100005],p,tp,ans;
int n,m;
int main()
{
	freopen("candy.in","r",stdin),freopen("candy.out","w",stdout);
	scanf("%d%d%lld",&n,&m,&p);
	for(int i=1;i<=m;++i)
	{
		for(int j=1;j<=n;++j)
		{
			scanf("%lld",&sum[i][j]);
			sum[i][j]=(sum[i][j]+sum[i][j-1])%p;
		}
	}
	if(m==3)
	{
		for(int i=1;i<=n;++i)
		{
			tp=(sum[1][i]-sum[2][i-1]+p)%p;
			se.insert(tp);
			tp=(sum[3][n]-sum[3][i-1]+sum[2][i]+p)%p;
			it=se.lower_bound(p-tp);
			ans=max(ans,(tp+*(--it))%p);
		}
		printf("%lld\n",ans);
		return 0;
	}
	for(int i=1;i<=n;++i)
		ans=max(ans,(sum[1][i]+sum[2][n]-sum[2][i-1]+p)%p);
	printf("%lld\n",ans);
	return 0;
}

T3 游戏

题意:给定有向图,你可以删除一个点的所有入边,代价\(w1_{i}\),或所有出边,代价\(w2_{i}\)(可以两个都删)。求删去所有边的最小代价。
题解:最小点权覆盖\(\to\)最小割。
CSP考网络流我当场就把这个电脑屏幕吃掉
代码就放std吧

#include<bits/stdc++.h>
using namespace std;
#define INF 1e9
struct node
{
    int begin,end,value,next;
}edge[10410];
int cnt,Head[240],S,T,dis[240],q[240],cur[240];
void addedge(int bb,int ee,int vv)
{
    edge[++cnt]=(node){bb,ee,vv,Head[bb]};
    Head[bb]=cnt;
}
void addedge1(int bb,int ee,int vv)
{
    addedge(bb,ee,vv);addedge(ee,bb,0);
}
int read()
{
    int s=0,fh=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
    return s*fh;
}
int BFS()
{
    int head,tail,u,v,i;
    head=0;tail=1;q[tail]=S;
    memset(dis,-1,sizeof(dis));dis[S]=0;
    while(head!=tail)
    {
        head++;
        if(head==230) head=0;
        u=q[head];
        for(i=Head[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].end;
            if(edge[i].value>0&&dis[v]<0)
            {
                dis[v]=dis[u]+1;
                tail++;
                if(tail==230) tail=0;
                q[tail]=v;
            }
        }
    }
    if(dis[T]<=0) return 0;
    return 1;
}
int DFS(int u,int minflow)
{
    int used=0,ans=0,i,v;
    if(u==T)return minflow;
    for(i=cur[u];i!=-1;i=edge[i].next)
    {
        v=edge[i].end;
        if(edge[i].value>0&&dis[v]==dis[u]+1)
        {
            ans=minflow-used;
            ans=DFS(v,min(ans,edge[i].value));
            edge[i].value-=ans;
            edge[i^1].value+=ans;
            used+=ans;
            if(minflow==used) return minflow;
        }
    }
    if(used==0) dis[u]=-1;
    return used;
}
int Dinic()
{
    int maxflow=0,ans=0,i;
    while(BFS())
    {zongjie
        for(i=1;i<=T;i++) cur[i]=Head[i];
        ans=DFS(S,INF);
        if(ans==0) break;
        maxflow+=ans;
    }
    return maxflow;
}
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    int n,m,i,u,v,w1,w2;
    n=read();m=read();
    S=2*n+1;T=S+1;//拆点
    memset(Head,-1,sizeof(Head));cnt=1;
    for(i=1;i<=n;i++)
    {
        w1=read();
        addedge1(i+n,T,w1);
    }//割入边
    for(i=1;i<=n;i++)
    {
        w2=read();
        addedge1(S,i,w2);
    }//割出边
    for(i=1;i<=m;i++)
    {
        u=read();v=read();
        addedge1(u,v+n,INF);
    }//原边流量为inf
    printf("%d",Dinic());
    return 0;
}
posted @ 2019-11-02 17:13  123789456ye  阅读(8)  评论(0)    收藏  举报