CF1119 Global Round 2

CF1119A Ilya and a Colorful Walk

  • 這題二分是假的.. $1,2,1,2,1$ 有間隔爲 $3$ 的,但沒有間隔爲 $2$ 的.開始被 $hack$ 了一次.後來改過來了.
  • 個人作法:掃一遍,記錄每一個顏色第一次出現的位置,並存入一個 $set$ 中,若當前顏色未出現,就更新位置,存入 $set$ ,不然將那個位置刪除.而後查詢一次 $set$ 中最小元素.最後再把那個位置插入回去.
  • 官方題解:最遠距離兩個端點中必定包含 $1$ 或 $n$ 中至少一個.若 $c_i\not =c_j,1<i<j<n$ ,那麼若是 $c_1,c_n$ 不一樣,那麼端點能夠直接選 $1,n$ ,不然若 $c_1=c_n$ ,那麼 $c_1\not = c_j,c_i\not =c_n$ 至少有一個成立,端點也會拓展到邊界上.
  • 找與 $1​$ 顏色不一樣的點與 $1​$ 的最遠距離,與 $n​$ 顏色不一樣的點與 $n​$ 的最遠距離取 $\max​$ 便可.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
	int out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		fh=-1,jp=getchar();
	while (jp>='0'&&jp<='9')
		out=out*10+jp-'0',jp=getchar();
	return out*fh;
}
int n;
const int MAXN=3e5+10;
int c[MAXN];
int check(int x)
{
	for(int i=1;i+x<=n;++i)
		if(c[i]!=c[i+x])
			return 1;
	return 0;
}
int pos[MAXN];
set<int> s;
int main()
{
	n=read();
	s.insert(n+1);
	int ans=0;
	for(int i=1;i<=n;++i)
		{
			int x=read();
			int y=pos[x];
			if(y)
				s.erase(y);
			int p=*s.begin();
			ans=max(ans,i-p);
			if(!pos[x])
				pos[x]=i;
			if(pos[x])
				s.insert(pos[x]);
		}
	cout<<ans<<endl;
	return 0;
}

CF1119B Alyona and a Narrow Fridge

  • 這題二分是真的,能放下前 $k$ 個顯然就能放下前 $k-1$ 個嘛.因而二分答案,判斷放前 $k$ 個是否可行.這裏貪心放,最大的和次大的放在一塊兒,後面同理,排序後兩個兩個放下來便可.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define mp make_pair
inline int read()
{
	int out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		fh=-1,jp=getchar();
	while (jp>='0'&&jp<='9')
		out=out*10+jp-'0',jp=getchar();
	return out*fh;
}
int n,h;
const int MAXN=1e3+10;
int a[MAXN];
int b[MAXN],tp=0;
bool check(int k)
{
	for(int i=1;i<=k;++i)
		b[i]=a[i];
	sort(b+1,b+1+k);
	int f=0,rs=h;
	for(int i=k;i>=1;--i)
	{
		if(!f)
		{
			rs-=b[i];
			if(rs<0)
				return false;
		}
		f^=1;
	}
	return true;
}
int main()
{
	n=read(),h=read();
	int s=0;
	for(int i=1;i<=n;++i)
		a[i]=read();
	int L=1,R=n;
	int ans=0;
	while(L<=R)
	{
		int mid=(L+R)>>1;
		if(check(mid))
			ans=mid,L=mid+1;
		else
			R=mid-1;
	}
	cout<<ans<<endl;
	return 0;
}

CF1119C Ramesses and Corner Inversion

  • 注意到這個翻轉操做只改變四個角落的值,不會改變每一行每一列的 $1$ 個數的奇偶性.
  • 那麼如有一行/列 $A,B$ 奇偶性不一樣,顯然不合法.
  • 不然?對於每一個不一樣的位置 $(x,y)$ ,咱們都選擇它做爲右下角, $(1,1)$ 做爲左上角進行操做.這樣全部不一樣的地方都被修改到同樣了,而 $A,B$ 每一行/列奇偶性都相同,多修改的部分 $(1,1),(1,y),(1,x)$ 剛好抵消, $A$ 就變成了 $B$ ,因此必定合法.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
	int out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		fh=-1,jp=getchar();
	while (jp>='0'&&jp<='9')
		out=out*10+jp-'0',jp=getchar();
	return out*fh;
}
const int MAXN=512;
int a[MAXN][MAXN],b[MAXN][MAXN];
int main()
{
	int n=read(),m=read();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			a[i][j]=read();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			b[i][j]=read();
	for(int i=1;i<=n;++i)
	{
		int s1=0,s2=0;
		for(int j=1;j<=m;++j)
			s1+=a[i][j],s2+=b[i][j];
		s1&=1,s2&=1;
		if(s1!=s2)
			return puts("No"),0;
	}
	for(int j=1;j<=m;++j)
	{
		int s1=0,s2=0;
		for(int i=1;i<=n;++i)
			s1+=a[i][j],s2+=b[i][j];
		s1&=1,s2&=1;
		if(s1!=s2)
			return puts("No"),0;
	}
	puts("Yes");
	return 0;
}

CF1119D Frets On Fire

  • 題面太鬼畜了...建議直接看 $Formally$ 那一段.c++

  • 首先容易發現, $s$ 數組的順序對答案是不影響的.因此咱們能夠先將 $s$ 從小到大排序.數組

  • 每次詢問 $(l,r)$ ,對於每一個 $s_i$ ,它所貢獻的數就是 $[s_i+l,s_i+r]$ 這一段,那麼就等價於給了 $n$ 條長度同樣的線段,問覆蓋的長度.spa

  • 能夠考慮用整個區間 $[s_1+l,s_n+r]$ 的長度減去中間沒有覆蓋到的部分.容易發現這樣的部分只可能出如今兩條相鄰線段之間,能夠直接用 $\max(s_{i+1}+l-s_i-r-1,0)$ 來計算.那麼此次詢問的答案就是 $$ ans=s_n+r-s_1-l+1-\sum_{i=1}^{n-1} \max(s_{i+1}+l-s_i-r-1,0)\ =s_n+r-s_1-l+1-\sum_{i=1}^{n-1} \max(s_{i+1}-s_i-(r-l+1),0) $$rest

  • 記 $b_i=s_{i+1}-s_i$ ,將 $b_i$ 排序後記錄一下前綴和,詢問時二分找出 $b_i\geq r-l+1$ 的第一個位置,只算後面的部分便可.時間複雜度 $O(nlogn+qlogn)$ .code

#include<bits/stdc++.h>
#define inf (1e18)+10
using namespace std;
typedef long long ll;
inline ll read()
{
	ll out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		fh=-1,jp=getchar();
	while (jp>='0'&&jp<='9')
		out=out*10+jp-'0',jp=getchar();
	return out*fh;
}
const int MAXN=1e6+10;
ll n,a[MAXN];
ll b[MAXN];
ll sum[MAXN];
int main()
{
	n=read();
	for(int i=1;i<=n;++i)
		a[i]=read();
	sort(a+1,a+1+n);
	for(int i=1;i<n;++i)
		b[i]=a[i+1]-a[i];
	sort(b+1,b+n);
	for(int i=1;i<n;++i)
		sum[i]=sum[i-1]+b[i];
	int Q=read();
	while(Q--)
	{
		ll l=read(),r=read();
		ll s=r-l+1;
		ll ans=a[n]+r-a[1]-l+1;
		if(s>b[n-1])
		{
			cout<<ans<<' ';
			continue;
		}
		int p=lower_bound(b+1,b+n,s)-b;	
		ans-=sum[n-1]-sum[p-1];
		ans+=1LL*(n-p)*s;
		cout<<ans<<' ';
	}
	return 0;
}

CF1119E Pavel and Triangles

  • 能夠發現, $2^i+2^j>2^k,i\leq j \leq k$ 有解,只多是 $i\leq j,k=j$ .
  • 那麼直接貪心選,每次讀入了 $x$ 個 $2^i$ ,就先嚐試用兩個 $i$ 與以前剩下的任意一個 $j$ 配對,再嘗試 $(i,i,i)$ 三個配對,再將剩餘的留着,後面再用.
  • 爲何要先嚐試 $(i,i,i)$ 三個配對呢?由於若是不進行這一步,它在以後的步驟中每想造成一個三角形就還須要 $2$ 個木棍構成 $(i,j,j)$ 的形式,顯然劣於 $(i,i,i)$ 直接配對.
  • 官方證實.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
	int out=0,fh=1;
	char jp=getchar();
	while ((jp>'9'||jp<'0')&&jp!='-')
		jp=getchar();
	if (jp=='-')
		fh=-1,jp=getchar();
	while (jp>='0'&&jp<='9')
		out=out*10+jp-'0',jp=getchar();
	return out*fh;
}
const int MAXN=3e5+10;
int a[MAXN];
ll ans=0,rest=0;
int main()
{
	int n=read();
	for(int i=1;i<=n;++i)
		{
			int x=read();
			ll p=min(1LL*x/2,rest);
			ans+=p;
			rest-=p;
			x-=p*2;
			ans+=x/3;
			x%=3;
			rest+=x;
		}
	cout<<ans<<endl;
	return 0;
}
相關文章
相關標籤/搜索