E.Oversleeping
题目描述
给定 (x,y,p,q),求最小的 (t) 满足下面两个等式((k_1,k_2geq 0)):
((p+q)k_1+pleq t<(p+q)k_1+p+q)
((2x+2y)k_2+xleq t<(2x+2y)k_2+x+y)
(1leq x,pleq 10^9,1leq y,qleq 500)
解法
要善于观察数据范围,你看 (y,qleq 500) 就应该知道他们是可以枚举的,我们枚举 (a<y,b<q),因为不等式可以看成若干个区间,所以我们枚举的是和区间左端点的距离,然后用两种方式表示 (t) 可以得到:
化简一下就可以得到:
然后就可以用 ( t exgcd) 了,先判断有无解(右边是否被 (gcd) 整除),然后可以求出下面不等式的解:
然后得到 (k_1=k_1' imesfrac{b-a+x-p}{gcd(p+q,2x+2y)},k_2=-k_2' imesfrac{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 imes y imes q imes 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
",ans);
}