链接:https://codeforces.com/contest/1501
A. Alexey and Train
看懂题目后直接模拟即可,我这里令 t 是每次出发的时间。
#include <bits/stdc++.h>
using namespace std;
#define N 105
long long n,a[N],b[N],tt[N];
void solve()
{
long long tmp;
scanf("%lld",&n);
for (int i=1; i<=n; i++)
scanf("%lld%lld",&a[i],&b[i]);
for (int i=1; i<=n; i++)
scanf("%lld",&tt[i]);
long long t=0;
for (int i=1; i<n; i++)
{
tmp=t+a[i]-b[i-1]+tt[i]+(b[i]-a[i]+1)/2;
t=max(tmp,b[i]);
}
t+=a[n]-b[n-1]+tt[n];
printf("%lld\n",t);
}
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
solve();
}
return 0;
}
B. Napoleon Cake
从后往前,用一个变量记录该处往下还可以浇多少个,每次维护一下就行了。
#include <bits/stdc++.h>
using namespace std;
int n,a[200005],f[200005];
void solve()
{
scanf("%d",&n);
for (int i=1; i<=n; i++)
{
f[i]=0;
scanf("%d",&a[i]);
}
int cnt=0;
for (int i=n; i>0; i--)
{
cnt=max(cnt,a[i]);
f[i]= (cnt>0);
cnt--;
}
for (int i=1; i<=n; i++)
printf("%d ",f[i]);
puts("");
}
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
solve();
}
return 0;
}
C. Going Home
这个技巧要记住, 四个数 abcd, a+d=b+c,即 a-b=c-d,那么由于 1≤ai≤2.5⋅1e6 ,任意两个数的差最多就 2.5*1e6 种, n 个数里面取两个数又有平方级别个取法,那么只要 n 平方级别大于 2.5e6 就行了,也就是说给的 200000 个数中只要取大概 5000 个数就行了。
(会发现,只有数少的时候才可能出现 NO 的情况,要是很多数的话(比如5000),肯定是有解的)
至于程序中的排序,我是想排完序相同的数会挤到一起,那选前5000个数可能答案出来快一点?
#include <bits/stdc++.h>
using namespace std;
int n;
int a[200005],c[200005];
vector<pair<int,int>> f[5000005];
bool cmp(int x, int y){return a[x]<a[y];}
#define I c[i]
#define J c[j]
void solve()
{
scanf("%d",&n);
for (int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
c[i]=i;
}
sort(c+1,c+n+1,cmp);
for (int i=1,mi=min(n,5000); i<mi; i++)
{
for (int j=i+1; j<=mi; j++)
{
int sum=a[I]+a[J];
if (!f[sum].empty())
{
for (auto A: f[sum])
{
if (A.first!=I && A.first!=J && A.second!=I && A.second!=J)
{
puts("YES");
printf("%d %d %d %d\n",A.first, A.second, I,J);
return;
}
}
}
f[sum].emplace_back(make_pair(I,J));
}
}
puts("NO");
}
int main()
{
solve();
return 0;
}
D. Two chandeliers
因为 ai 互不相等,所以把不同颜色分开来考虑。
比如对于颜色 colr,a中在第 i 个, b 中在第 j 个,那么它们一次相遇点为 t ,则有
t= x1*n+i = x2*m+j
,这里 x1 x2 都是整数,变形一下
x1*n-x2*m=j-i
,就变成求不定方程的解了,扩展gcd来一下。
之后得出每种颜色第一次相遇的地方存到 s
数组里面(不会相遇的地方我用 -1
代替),每种颜色第一次相遇后,每过 lcm(n,m) 才会相遇一次。
之后我用了二分答案的方法,判断条件是对于时间 M ,要是不同次数大于等于 k ,那么就返回 1 ,否则返回 0。
这样就得到答案了,时间复杂度是 O(max(n,m)*lg(k)) 吧大概……
#include <bits/stdc++.h>
using namespace std;
long long n,m,k,nmgcd,nmlcm;
long long gcd(long long x, long long y){return y ? gcd(y,x%y) : x;}
long long lcm(long long x, long long y)
{
long long tt=gcd(x,y);
tt=x*y/tt;
return tt;
}
long long exgcd(long long aa,long long bb,long long &x,long long &y)//扩展欧几里得算法
{
if(bb==0)
{
x=1;y=0;
return aa; //到达递归边界开始向上一层返回
}
long long r=exgcd(bb,aa%bb,x,y);
long long temp=y; //把x y变成上一层的
y=x-(aa/bb)*y;
x=temp;
return r; //得到a b的最大公因数
}
#define N 500005
long long a[N],b[N],fa[N<<1],fb[N<<1],s[N<<1],MM;
bool check(long long x)
{
long long cnt=x;
for (long long i=MM; i; i--) if (s[i]>0)
{
if (x>=s[i])
{
cnt-=(x-s[i])/nmlcm+1;
}
}
return cnt>=k;
}
void solve()
{
scanf("%lld%lld%lld",&n,&m,&k);
MM=max(n,m)<<1;
for (long long i=1; i<=n; i++)
{
scanf("%lld",&a[i]);
fa[a[i]]=i;
}
for (long long i=1; i<=m; i++)
{
scanf("%lld",&b[i]);
fb[b[i]]=i;
}
nmgcd=gcd(n,m);
nmlcm=lcm(n,m);
for (long long colr=MM; colr; colr--)
{
if (fa[colr]==0 || fb[colr]==0 || (fb[colr]-fa[colr])%nmgcd!=0)
{
s[colr]=-1;
continue;
}
if (fa[colr]==fb[colr])
{
s[colr]=fa[colr];
continue;
}
long long x1,x2,tmp;
exgcd(n,m,x1,x2);
x1*=((fb[colr]-fa[colr])/nmgcd);
x2*=((fb[colr]-fa[colr])/nmgcd);
tmp=x1*n+fa[colr];
tmp=((tmp-1)%nmlcm+nmlcm)%nmlcm+1;
s[colr]=tmp;
}
long long L=1,R=(1ll<<61),M,ans;
for (; L<R; )
{
M=(L+R)>>1;
if (check(M))
ans=R=M;
else
L=M+1;
}
printf("%lld\n",ans);
}
int main()
{
solve();
return 0;
}
/*
3 8 41
1 3 2
1 6 4 3 5 7 2 8
*/