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);
}
}