Caddi Programming Contest 2021(AtCoder Beginner Contest 193)

E.Oversleeping

题目描述

给定 \(x,y,p,q\),求最小的 \(t\) 满足下面两个等式(\(k_1,k_2\geq 0\)):

\((p+q)k_1+p\leq t<(p+q)k_1+p+q\)

\((2x+2y)k_2+x\leq t<(2x+2y)k_2+x+y\)

\(1\leq x,p\leq 10^9,1\leq y,q\leq 500\)

解法

要善于观察数据范围,你看 \(y,q\leq 500\) 就应该知道他们是可以枚举的,我们枚举 \(a<y,b<q\),因为不等式可以看成若干个区间,所以我们枚举的是和区间左端点的距离,然后用两种方式表示 \(t\) 可以得到:

\[(p+q)k_1+p+a=(2x+2y)k_2+x+b \]

化简一下就可以得到:

\[(p+q)k_1-(2x+2y)k_2=b-a+x-p \]

然后就可以用 \(\tt exgcd\) 了,先判断有无解(右边是否被 \(\gcd\) 整除),然后可以求出下面不等式的解:

\[(p+q)k_1'+(2x+2y)k_2'=\gcd(p+q,2x+2y) \]

然后得到 \(k_1=k_1'\times\frac{b-a+x-p}{\gcd(p+q,2x+2y)},k_2=-k_2'\times\frac{b-a+x-p}{\gcd(p+q,2x+2y)}\),但是这两个解不一定合法,我们要把它们都调整成非负数, \(k_1,k_2\) 可以同时分别加上 \(\frac{2x+2y}{\gcd}\)\(\frac{p+q}{\gcd}\),但是还要调整成最优解,也就是 \(k_1\) 要是最小的非负整数解,那么模一下即可。

时间复杂度 \(O(T\times y\times q\times \log x)\)

#include <cstdio>
#include <iostream>
using namespace std;
#define int __int128
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int T,x,y,p,q,ans;
int gcd(int a,int b)
{
	return !b?a:gcd(b,a%b);
}
int exgcd(int a,int b,int &x,int &y)
{
	if(!b) {x=1;y=0;return a;}
	int d=exgcd(b,a%b,y,x);
	y-=x*(a/b);
	return d;
}
void write(int x)
{
	if(x<=9) {putchar(x+'0');return ;}
	write(x/10);putchar(x%10+'0');
} 
signed main()
{
	T=read();
	while(T--)
	{
		x=read();y=read();p=read();q=read();
		ans=1e36;
		for(int a=0;a<q;a++)
			for(int b=0;b<y;b++)
			{
				int r=b-a+x-p;
				if(r%gcd(p+q,2*x+2*y)) continue;
				int k1=0,k2=0,d=exgcd(p+q,2*x+2*y,k1,k2);
				k1*=r/d;k2=-k2;k2*=r/d;
				int z1=(2*x+2*y)/d,z2=(p+q)/d;
				if(k1<0)
				{
					int t=(-k1+z1-1)/z1;
					k1+=t*z1;k2+=t*z2;
				}
				if(k2<0)
				{
					int t=(-k2+z2-1)/z2;
					k1+=t*z1;k2+=t*z2;
				}
				k1%=z1; 
				ans=min(ans,k1*(p+q)+a+p);
			}
		if(ans==1e36) puts("infinity");
		else write(ans),puts("");
	}
}

F.Zebraness

题目描述

点此看题

解法

出题人水平不够,我们来看一个加强版,这样就可以解决这道题了。

如果每个点选黑选白有代价,同时选黑或同时选白有代价,我们可以建出下面这个图:

那么割掉的是 \(1,2,3\),或者是 \(4,5,6\),或者是 \(1,2,4,6\),或者是 \(1,3,4,5\),源点理解成染黑,汇点理解成染白,那么也就是如果同时染白会得到 \(4\) 的贡献,同时染黑会得到 \(1\) 的贡献。

回归本题,对于钦定的颜色我们需要连 \(inf\) 的边,对于 ? 则不用连边,由于这道题是一个选黑一个选白有代价,所以说一开始可以对矩阵二分图染色,改一下连的边即可。

#include <cstdio>
#include <queue>
using namespace std;
const int M = 100005;
const int inf = 0x3f3f3f3f;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,S,T,tot,ans,cnt,f[M],cur[M],dis[M];char s[M];
int dx[2]={1,0},dy[2]={0,1};
struct edge
{
	int v,c,next;
}e[10*M];
void add(int u,int v,int c)
{
	e[++tot]=edge{v,c,f[u]},f[u]=tot;
	e[++tot]=edge{u,0,f[v]},f[v]=tot;
}
int id(int x,int y)
{
	return (x-1)*n+y;
}
int bfs()
{
	for(int i=0;i<=cnt;i++) dis[i]=0;
	queue<int> q;q.push(S);dis[S]=1;
	while(!q.empty())
	{
		int u=q.front();q.pop();
		if(u==T) return 1;
		for(int i=f[u];i;i=e[i].next)
		{
			int v=e[i].v;
			if(e[i].c>0 && !dis[v])
			{
				dis[v]=dis[u]+1;
				q.push(v);
			}
		}
	}
	return 0;
}
int dfs(int u,int ept)
{
	if(u==T) return ept;
	int flow=0,tmp=0;
	for(int &i=cur[u];i;i=e[i].next)
	{
		int v=e[i].v;
		if(e[i].c>0 && dis[v]==dis[u]+1)
		{
			tmp=dfs(v,min(ept,e[i].c));
			if(!tmp) continue;
			e[i].c-=tmp;
			e[i^1].c+=tmp;
			flow+=tmp;
			ept-=tmp;
			if(!ept) break;
		}
	}
	return flow;
}
signed main()
{
	n=read();S=0;cnt=T=n*n+1;tot=1;
	for(int i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for(int j=1;j<=n;j++)
		{
			if((i+j)&1)
			{
				if(s[j]=='B') add(S,id(i,j),inf);
				if(s[j]=='W') add(id(i,j),T,inf);
			}
			else
			{
				if(s[j]=='W') add(S,id(i,j),inf);
				if(s[j]=='B') add(id(i,j),T,inf);
			}
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			for(int k=0;k<2;k++)
			{
				int x=i+dx[k],y=j+dy[k];
				if(x<1 || x>n || y<1 || y>n) continue;
				cnt++;
				add(S,cnt,1);
				add(cnt,id(x,y),inf);
				add(cnt,id(i,j),inf);
				cnt++;
				add(id(x,y),cnt,inf);
				add(id(i,j),cnt,inf);
				add(cnt,T,1);
				ans+=2;
			}
		}
	while(bfs())
	{
		for(int i=0;i<=cnt;i++) cur[i]=f[i];
		ans-=dfs(S,inf);
	}
	printf("%d\n",ans);
}
posted @ 2021-05-24 22:52  C202044zxy  阅读(66)  评论(0编辑  收藏  举报