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\) 可以得到:
化简一下就可以得到:
然后就可以用 \(\tt exgcd\) 了,先判断有无解(右边是否被 \(\gcd\) 整除),然后可以求出下面不等式的解:
然后得到 \(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);
}