Educational Codeforces Round 100 (Rated for Div. 2) 补题情况
战况(被hack掉一个 -2)
A. Dungeon
数学题,实际上一次抹掉三个同时,并且还能再抹掉6个所以一波就能干掉9个,至于他怎么干的完全可以不用去考虑,这里贪心即可。但是要注意看他干了几波,如果干的波数小于\(min(a,b,c)\)的话,那么肯定也是不行的。
所以首先判断\((a+b+c)\mod9 == 0?\) 如果可以再判断是否\(\frac{a+b+c}{9}\leq min(a,b,c)\) 即可
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
long long a,b,c,d=INT_MAX;
scanf("%lld%lld%lld",&a,&b,&c);
long long s=a+b+c;
if(s%9==0)
{
s/=9;
if(s<=min(min(a,b),c)) puts("YES");
else puts("NO");
}
else puts("NO");
}
}
B. Find The Array
构造题,两种做法。
第一种是直接构造所有的\(a[i]\)的同一位数的二进制数即可。这样能保证所有的整除关系。
例如\(a[i]=5\)那么\(5=(101)_2\) 我们构造\(b[i]=4=(100)_2\)这样我们的差值\(|a[i]-b[i]|=1=(001)_2\)可以证明这个插值一定是小于等于\(\lfloor\frac{a[i]}{2}\rfloor\)的。因为我之前的第一位已经占了一个一,我数向下取整除以二就是右移一位,并且我之前前面一定占有至少相同的一,所以相差不会大于要求。
#include <bits/stdc++.h>
using namespace std;
int a[1005];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int now=1;
for(int i=1;i<=n;i++)
{
int now=1;
while(1)
{
if(now*2>a[i])
{
cout<<now<<" ";
break;
}
now*=2;
}
}
cout<<"\n";
}
}
第二种做法是,我们可以认为\(S=\sum_{i=1}^{n}a[i]=S_{odd}+S_{even}\)也就是说我们总和等于原数列的奇数项加上偶数项,我们看哪一项大就把\(b[i]\)对应的等于\(a[i]\)其他都设置成为1,这样的话\(2\sum_{i=1}^{n}|a[i]-b[i]|=2(a[1]+a[3]+...+a[n-1]-\frac{n}{2})=2S_{odd}-n\)(假设n是一个偶数,并且偶数项大于等于奇数项)。因为\(S_{odd}\leq S_{even}\)所以\(2S_{odd}\leq S\),所以\(2S_{odd}-n\leq S\),所以这么分的话\(2\sum_{i=1}^{n}|a[i]-b[i]|\leq S\)满足题目要求。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[105],s1,s2;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
s1=s2=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(i&1) s1+=a[i];
else s2+=a[i];
}
if(s1<=s2)
{
for(int i=1;i<=n;i++) if(i&1) printf("1 ");else printf("%lld ",a[i]);
}
else
{
for(int i=1;i<=n;i++) if(i&1) printf("%lld ",a[i]);else printf("1 ");
}
puts("");
}
}
C. Busy Robot
直接模拟的题,按照题意模拟即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t[100005],x[100005];
set<ll> st;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld%lld",&t[i],&x[i]);
t[n+1]=INT_MAX;
t[n+1]+=t[n+1];
ll tm=0,ans=0,pos=0,l=0,r=0,ltm=0,f=1,lpos=0;
for(int i=1;i<=n;i++)
{
if(t[i]>=tm)
{
ll d1=0;
ll d2=d1+t[i+1]-t[i];
if(x[i]>=pos)
{
f=1;
l=pos+d1;
r=pos+d2;
}
else
{
f=-1;
r=pos-d1;
l=pos-d2;
}
if(x[i]>=l&&x[i]<=r) ans++;
ltm=t[i];
tm=t[i]+llabs(pos-x[i]);
lpos=pos;
pos=x[i];
}
else
{
ll d1=t[i]-ltm;
ll d2=min(tm,t[i+1])-ltm;
if(f==1)
{
l=lpos+d1;
r=lpos+d2;
}
else
{
r=lpos-d1;
l=lpos-d2;
}
if(x[i]>=l&&x[i]<=r) ans++;
}
}
printf("%lld\n",ans);
}
}
D. Pairs
给你\(2n\)个整数\(1,2,3,4,...,2n\)让你从中分出\(n\)个数对并且从中任意选出\(x\)个数对的最小值为\(b[i]\),从\(n-x\)个数对中选出最大值为\(b[i]\),且满足对于选出来的\(b[i]\)要等于\(a[i]\)并且\(a[i]\)为输入的数组,求\(0\leq x\leq n\)中有多少个\(x\)能够满足要求。
首先找出\(2n\)中剩下的数不在\(a[i]\)中的让他们组成\(c[i]\),然后把\(c[i]\)排序,顺便把\(a[i]\)也排序,因为我们任意选出数对来构造\(b[i]\)所以原来数组\(a[i]\)的顺序也无关紧要。如果我们要选择一个数对让他们的小的数成为\(b[i]\)那么我对应的这个位置上的\(a[i]\)必须得从\(c\)数组中有比我大的数才可以否则根本无法实现,反之亦然(vice versa)。于是我们就可以贪心的看看每个数到底有几个比他大的数在\(c\)数组中,有几个比他小的数。
这里还需要发现一个事,就是我如果给定的资源也就是数的个数是合适的话,我一定能够分配好,不管怎么分配。那么我只要确定好上下界限,也就是\(x\)的上下界限\(l,r\)即可,答案就是\(r-l+1\)因为我可以用的资源是够的,所以一定能够分配好。
但是我们怎么求的\(l,r\)呢?
实际上\(r\)就是最多的能有在\(c\)中比\(a[i]\)大的数的个数,这样就可以用小的数构造\(b[i]\)。
\(l\)就是\(n-最多的能有在c中比a[i]小的数的个数\)因为这些数没有比他们小的,只能用大的数构造\(b[i]\)。
所以现在问题就是找上面的什么比\(a[i]\)大比\(a[i]\)小的什么的个数了。
我们需要考虑一下这个数据
2
2 3
可以发现1不在\(a[i]\)中并且比2和3都要小,但是我这个1只能分配个一个,所以我需要从左到右的去寻找,来判断一下是否能够分配。
同样的4都比2 3大所以要从右到左的去寻找,来判断一下是否能够分配。
最终答案就是\(r-l+1\)时间复杂度为\(O(NlogN)\)
#include <bits/stdc++.h>
using namespace std;
int mk[500005],a[500005],b[500005],maxn[500005],minn[500005],n;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int p=0,m1,m2,x=0,y=0,ans=0;
scanf("%d",&n);
for(int i=1;i<=2*n;i++) mk[i]=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),mk[a[i]]++;
for(int i=1;i<=2*n;i++) if(!mk[i]) b[++p]=i;
sort(b+1,b+1+p);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
{
m2=lower_bound(b+1,b+1+p,a[i])-b-1;
if(m2>y) y++;
}
for(int i=n;i;i--)
{
m1=n-(upper_bound(b+1,b+1+p,a[i])-b)+1;
if(m1>x) x++;
}
int l=n-y,r=x,L=l;
printf("%d\n",r-l+1);
}
}
小结
B不被hack就好了。。。A想的有点慢。