1. 程式人生 > 實用技巧 >Educational Codeforces Round 100 (Rated for Div. 2) 補題情況

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