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;
}
一切伟大的行动和思想,都有一个微不足道的开始。
There is a negligible beginning in all great action and thought.
There is a negligible beginning in all great action and thought.

浙公网安备 33010602011771号