1. 程式人生 > >【CF】Codeforces Round #505 (Div. 1 + Div. 2)

【CF】Codeforces Round #505 (Div. 1 + Div. 2)

終於上紫啦!

撒花!


刺激,一回二高就打CF,還好準備時間充裕,下了Firefox,調好Dev-C++,裝了CF-Predictor。(廣告預警)

強烈推薦外掛 CF-Predictor !讓你實時瞭解預計Rating Change,從而面向Rating做題(逃

各大瀏覽器外掛中心、Tampermonkey、搜尋CF-Predictor,一分錢不要,白白帶回家!

---以上是廣告時間---

下面是正題:HackCodeforces Round #505題解。


題解

A. Doggo Recoloring

題意:給你一個字串,每次操作你可以選擇一個出現過兩次或以上的字元,把它們全部變成你指定的另一個字元,你可以進行無限次操作,問你能否使得這個字串只含一種字元。

題解:很容易發現,如果這個字串中含有一個字元,它出現過兩次或以上,那麼你只需要把這幾個字元變成另一種在這個字串中出現過的字元,然後不停重複以上操作,最後得到的字串就一定只含有一種字元了。

證明是顯然的:若你能進行上述操作,那麼答案一定是Yes,否則這個字串不能進行任何操作,答案就是No(伏筆)。

所以就統計有沒有一個字元出現過兩次或以上。

快速碼完了交上去,螢幕上顯示著In queue,突然想到,n=1

咋沒有撤回提交功能啊。。。。。。o(╥﹏╥)o

還是怪自己不細心,Wrong answer on pretest 4,-50pts。

證明是顯然的:若你能進行上述操作,那麼答案一定是Yes,否則這個字串不能進行任何操作,答案就是No。n=1除外!!!!!一定是Yes!!!!!

Pretests passed,下一題。

 

B. Weakened Common Divisor

題意:給你n對數,讓你找一個大於1的數x,滿足x是每對數中其中一個的因子。

題解:一讀懂題,開始瞎猜。

lc:把每對數求lcm,把求完lcm的n個數求gcd不就是答案嗎。

於是大家一起瘋狂碼,lc:我WA了。

仔細一想,錯的!

。。。。。。

一看時間:00:18:10

別卡B題啊(伏筆)。

老實(naive)的我思考了一下,能不能把這個做法改一下,20分鐘後想到一種做法:把用上面的方法求得的答案取質因子。

正確性容易證明。

00:41:50  Pretests passed [pretests] 

咋花了41分鐘(伏筆)才做出B啊。。。。涼透。。。。

突然一想,複雜度對嗎?

然後往程式裡一輸入:

2
998244353 1000000007
998244353 1000000007

TLE!

求質因子極限要O(\sqrt{max(a_{i})*max(b_{i})}),然後兩個大質數一乘再開根,Boom!

Pretests:

這Pretest有何用!!!

做法推翻。。。涼透。。。

lc:不對,你把第一對數的兩個數都分解質因子,然後每個質因子暴力判就完了啊。

我怕是腦子抽了。

lc:00:45:53  Pretests passed [main tests]

然而我各種WA

01:10:09  Pretests passed  [main tests] 

咋01:10:09才過B啊。。。。。

一看分數:370

比A還少。。。。。

一定有人寫我之前的做法的,果斷鎖。

 

C. Plasticine zebra

題意:給你一個01串,你可以把這個字串從任何位置切開,兩邊各自翻轉,拼回來。可以進行無限多次。求你經過這些操作後能得到的字串中01相間子串的最長長度。

題解:就在碼B題的時候(就是lc過了B我還在各種WA的時候)

lc(就在我正後方一米):啊~~~~~我C過了!!!!!!!!!!!!!!

lc:就是你把這個串倍長,然後求它的最長01相間子串長度就可以了。

你也先等我過了B啊,大佬。

然後看到lc的status:

01:00:46  Pretests passed [pretests]

01:02:29  Hacked by cubercsl

同時lc:等等我C被hack了!

謝謝,我放心碼B題了,大佬。

lc:哦答案要與原串長度取min。我再交。

然後等了很久,沒有被hack。

應該是正解了。。。我剛好過了B,於是碼完C,Pretests passed。

我:真的是正解嗎,你要不要鎖一下看看別人怎麼寫。

lc:你鎖吧。

我:(狠心)反正我B鎖了,那我把C也鎖了吧!(切勿模仿,幸好沒有伏筆)

好像真的這樣做啊。

回宿舍的路上想到的粗略證明:把這個串進行操作後一定是倍長串的子串。

 

下面進入 Hackforces 講故事時間:

看D題,暫時沒有思路。

翻翻別人B題的程式碼,前幾個看來很正經,突然看到一個,怎麼這麼熟悉???

for(ll i=2;i*i<=ans;++i)
{
    if(ans%i==0)
    {
        cout<<i;
        return 0;
    }
}
cout<<ans;

這不就是我之前的做法嗎!

點下hack it!,輸入那組資料:

2
998244353 1000000007
998244353 1000000007

來不及猶豫了! 按下Hack按鈕

In queue...

心跳加速中...

狀態up!八分鐘後

這時候有個人來hack我的B題,然而他並沒有成功。我一看他的程式碼結尾,熟悉的for迴圈!

這個Room的B題貌似就沒有用那種做法的了,於是看看Locked的C題。原本沒抱太多希望,因為我們Room早有人把C題鎖了,讓我聯想到lc房的那位大佬,一看到有人沒取min就光速hack掉,於是我便以為我們Room鎖了C的人也把沒取min的hack了。

然而事實是這樣的:

這個人答案沒取min!

這個人程式碼好醜,但是答案沒取min!

這個人答案也沒取min!

然而這時候,CF-Predictor告訴我,我還是會掉Rating的(伏筆)!

那死也要把D題暴力打出來,FST就FST!

 

D. Recovering BST

題意:給你n個數,讓你判斷,是否用這些陣列成一棵二叉搜尋樹,使得每條邊上的兩個數的gcd不為1。

題解:不會啊。我只會打暴力,正解是O(n^3)的dp啊。

場上寫了個O(n^4)的暴搜,過了Pretest。

還把System test過了!!!

也許複雜度是對的

好吧其實原因可能是用了bitset壓位,常數極小。

 


 

程式碼

A

#include <bits/stdc++.h>
using namespace std;

int cnt[30];

int main()
{
	int n;
	string s;
	cin >> n >> s;
	for(int i=0;i<s.length();++i)++cnt[s[i]-'a'];
	for(int i=0;i<26;++i)if(cnt[i]>=2){puts("Yes");return 0;}
	if(n==1)puts("Yes");
	else puts("No");
}

 B

#include <bits/stdc++.h>
using namespace std;

int s[10000001],isp[10000001];
bool flag[10000001];

int main()
{
	int n,a,b;
	scanf("%d",&n);
	scanf("%d%d",&a,&b);
	if(n==1){if(a==1)printf("%d\n",b==1?-1:b);else printf("%d\n",a);return 0;}
	for(register int i=2;i<=45000;++i)
	{
		bool check=true;
		for(register int j=2;j<=sqrt(i);++j)
			if(i%j==0)
			{
				check=false;
				break;
			}
		isp[i]=check;
	}
	for(int i=2;i<=sqrt(a);++i)
	{
		if(a%i==0 && isp[i])s[++s[0]]=i;
		while(a%i==0)a/=i;
	}
	if(a>1)
		s[++s[0]]=a;
	for(int i=2;i<=sqrt(b);++i)
	{
		if(b%i==0 && isp[i])s[++s[0]]=i;
		while(b%i==0)b/=i;
	}
	if(b>1)
		s[++s[0]]=b;
	memset(flag,true,sizeof(flag));
	for(int i=2;i<=n;++i)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		for(int j=1;j<=s[0];++j)
		{
			if(a%s[j]!=0 && b%s[j]!=0)flag[j]=false;
		}
	}
	int ans=-1;
	for(int i=1;i<=s[0];++i)if(flag[i])ans=s[i];
	printf("%d\n",ans);
}

C

#include <bits/stdc++.h>
using namespace std;

int main()
{
	string s;
	cin >> s;
	string t=s;
	s+=t;
	int ans=1,now=1;
	for(int i=1;i<s.length();++i)
	{
		if(s[i]==s[i-1])now=1;
		else ++now;
		ans=max(ans,now);
	}
	cout << min((int)t.length(),ans);
}

 D

#include<bits/stdc++.h>
using namespace std;

int n,a[701];
bitset<701> vis2[701][701],ans[701][701];
bool ok[701][701];

int check(int l,int r,int root)
{
	if(r<l)return true;
	if(l==r)return ok[l][root];
	if(vis2[l][r][root])return ans[l][r][root];
	for(int i=l;i<=r;++i)
		if(ok[i][root] && check(l,i-1,i) && check(i+1,r,i))
		{
			vis2[l][r][root]=1;
			ans[l][r][root]=1;
			return true;
		}
	vis2[l][r][root]=2;
	return false;
}

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		scanf("%d",a+i);
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
			ok[i][j]=__gcd(a[i],a[j])!=1;
		ok[0][i]=true;
		ok[i][0]=true;
	}
	if(check(1,n,0))puts("Yes");else puts("No");
}

比賽結束後大半部分的人都FST了,其實不做D也能漲的。

下一場Codeforces,Div.1見!