CF 979 Review

Hanggoash發表於2024-10-21

CF 979 Review

喜聞樂見的C題不鍛鍊碼力的場,可惜早早地做完了C之後就開始想D,到最後知道怎麼做了,但是寫不來程式碼。

實際上還是腦子不夠好使,想不出來簡單的寫法;只有複雜的思路,但卻沒有相應的碼力。

A

分析

很明顯的一個貪心,注意考慮一下邊界條件即可。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48); 
}
inline void out(int x){wr(x),putchar('\n');}
int n,m,T;
int main()
{
	re(T);
	int tmp;
	while(T--)
	{
		re(n);
		int mx=-1,mn=1000000,s=0;
		for(int i=1;i<=n;++i)
		{
			cin>>tmp;s+=tmp;
			mx=max(mx,tmp);
			mn=min(mn,tmp);
		}
		out(n*(mx-mn)-mx+mn);
	}
	return 0;
 } 				

B

分析

推式子題,用到了組合數的求和公式,也還是比較容易,最後得到的結論就是輸出 \(n-1\)\(0\) ,注意特判一下 \(n=1\) 的情況即可。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48); 
}
inline void out(int x){wr(x),putchar('\n');}
int n,m,T;
int main()
{
	re(T);
	while(T--)
	{
		re(n);
		if(n==1){puts("0");}
		else
		{
			for(int i=1;i<=n-1;++i)putchar('0');
			puts("1"); 
		}

	}
	return 0;
 } 

C

很好的一道思維題博弈論

分析

首先如果端位有 \(1\) 那麼肯定是先手贏。

開始的想法是,對於兩人中的任意一個人來說,在 \(11\) 中間進行操作都是沒有意義的,所以整個串可以縮寫為 \(010101...1010\) 的形式。

這樣看來那麼先手不論下在哪裡,後手都可以使得先手這一步變得無效,最後一定是後手贏。

交上去發現 WA 了。

問題在於縮寫的這個過程並不恰當。

假設有一個 \(0110\) 的串,如果先手在最中間放一個,那麼後手無論堵哪一個,下一個先手都可以再放一個 "|" 使得有一個 \(1\) 被完全包含,也就是最終的答案一定是 \(1\) 。推而廣之,只要有若干個連續的 \(1\) ,就一定能贏。

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48); 
}
inline void out(int x){wr(x),putchar('\n');}
int n,m,T;
char s[200010];
int main()
{
	re(T);
	while(T--)
	{
		re(n);
		scanf("%s",&s);
		if(s[0]=='1'||s[n-1]=='1')
		{
			puts("YES");
			goto A;
		}
		else 
		{
			for(int i=1;i<n;++i)
			{
				if(s[i]==s[i-1]&&s[i]=='1')
				{
					puts("YES");
					goto A;
				}
			}
		}
		puts("NO");
		A:;
	}
	return 0;
 } 

D

分析

很早就推出了一個結論:任意的 \(RRRRR...RLLLLL...L\) 一定可以透過氣泡排序的原理來使得整個子序列達到有序。

言下之意就是,\(LR\) 對應的一定是一個斷點 ,左邊無法往右,右邊無法往左,我們不妨用左邊的 \(L\) 對應的下標來代表這個斷點所在的位置。

想讓這個排列變得有序,我們必須讓所有元素回到其對應的位置上,設一個元素 \(x\) 現在的位置是 \(pos\) ,那麼它應該回到 \(x\) 的下標上。

也就是說我們需要 從 \(idx\rightarrow x\) 的路徑上是不間斷的,在我們對斷點的定義下,要求 \(idx\rightarrow(x-1)\)路徑中所有下標都不能是斷點

並且對於每一個元素都必須有以上性質成立。

那麼我們可以維護有哪些點被至少一條路徑依賴,並把其中所有斷點丟進一個set中,在修改操作的時候動態地進行插入和刪除。

如果在操作過後set裡面沒有斷點,也就是說所有路徑都是暢通的,這時候答案就是yes,否則就是no。

盲區

scanf字串的時候不要加取地址!!!

Code

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48); 
}
inline void out(int x){wr(x),putchar('\n');}
int n,m,T,q,pos;
char upd[200010];
int a[200010],s[200010];
int main()
{
	re(T);
	while(T--)
	{
		re(n),re(q);
		for(register int i=1;i<=n;++i)s[i]=0;
		for(register int i=1;i<=n;++i)
		{
			re(a[i]);
			s[min(i,a[i])]++;
			s[max(i,a[i])]--;		
		}
		scanf("%s",upd+1);
		set<int> err; 
		for(register int i=1;i<=n;++i)
		{
			s[i]+=s[i-1];
			if(upd[i]=='L'&&upd[i+1]=='R'&&i!=n&&s[i])
				err.insert(i);
		}
//		for(register int i=1;i<=n;++i)cout<<s[i]<<' ';
//		cout<<endl;
		auto modify=[&](int pos)
		{
			if(upd[pos]=='L')
			{
				if(upd[pos+1]=='R'&&pos!=n&&err.count(pos))
					err.erase(pos);
				if(upd[pos-1]=='L'&&pos!=1&&s[pos-1])
					err.insert(pos-1);
				upd[pos]='R';
			}
			else 
			{
				if(upd[pos-1]=='L'&&pos!=1&&err.count(pos-1))
					err.erase(pos-1);
				if(upd[pos+1]=='R'&&pos!=n&&s[pos])
					err.insert(pos); 
				upd[pos]='L';
			}
		};
		while(q--)
		{
			re(pos);
			modify(pos);	
			puts(err.empty()?"YES":"NO");
		}
	}
	return 0;
 } 
 /*
 3
5 3
1 4 2 5 3
RLRLL
2
4
3
8 5
1 5 2 4 8 3 7 6
RRLLRRRL
4
3
5
3
4
6 2
1 2 3 4 5 6
RLRLRL
4
5
 */

總結

非常緊迫的一個問題就是要強化自己的程式碼實現能力,可以去學一些巧妙的stl用法等。