【類並查集-思維】NOI.AC——CSP2019模擬 Day 5——圓

前言

發現自己又“獨樹一幟”了一回,和大家的思路都不同...可惜沒調出來,挖坑以後再調吧...

題目

本題下發文件下載

分析

(直接看正解見橫線以下)

自己的思路(沒調過):

如果要構成一個正K邊形,在圓上肯定要有K個相等的大線段,

設這K個相等的大線段長度爲len,len = C / k

這些大線段又由許多初始點構成的小線段構成

所以對於圓上的每個小線段d[ i ],有以下三種情況:(設已有的大線段數量爲cnt,已訪問過的線段爲tot)

1.d[ i ]=len:長度直接符合,cnt++

2.d[ i ]>len:因爲小線段不能拆分,於是直接無解,print “No”

3.d[ i ]<len:要和其他線段(長度也小於len)合起來,使得長度等於len,就要看是和其左邊的線段合起來,還是和右邊的線段合起來

最後如果tot=n且cnt=k,則“Yes”,否則“No”

我是用的搜索實現的,不過很遺憾,只有30分,錯因不明,只好學習別人的做法了


後來去問了一下某Tao大佬,好像說我沒有考慮和左右線段一起合起來的情況...


AC代碼思路:

形成K邊形時,選中的K個點肯定相距都爲len = C / k,所以對於每個點,找到和它相距len的點,

如果同屬於一個並查集就“Yes”,否則就加入一個並查集,沒有解就“No”

在一個並查集就相當於它們都屬於構成某K邊形的點or邊的集合

PS.我也不知道我理解對了沒有QAQ!

官方題解:

玄學搜索30分代碼

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5;
bool vis[MAXN+5];
int a[MAXN+5],d[2*MAXN+5];
int n,c,k;
int len;
void dfs(int id,int cnt,int tot)
{
	tot++,vis[id]=1;
	if(d[id]==len)
		cnt++;
	//printf("id:%d cnt:%d tot:%d d:%d\n",id,cnt,tot,d[id]);
	if(cnt==k&&tot==n)
	{
		printf("Yes\n");
		exit(0);
	}
	if(tot==n)
		return ;
	if(d[id]==len)
	{
		int x=id+1,y=id-1;
		if(x==n+1) x=1;
		if(y==0) y=n;
		if(!vis[x])
			dfs(x,cnt,tot);
		if(!vis[y])
			dfs(y,cnt,tot);
	}
	if(d[id]>len)
	{
		printf("No\n");
		exit(0);
	}
	if(d[id]<len)
	{
		int x=id+1,y=id-1;
		if(x==n+1) x=1;
		if(y==0) y=n;
		if(!vis[x]&&d[x]+d[id]<=len)
		{
			d[x]+=d[id];
			dfs(x,cnt,tot);
			d[x]-=d[id];
		}
		if(!vis[y]&&d[y]+d[id]<=len)
		{
			d[y]+=d[id];
			dfs(y,cnt,tot);
			d[y]-=d[id];
		}
	}
	vis[id]=0;
}
int main()
{
	scanf("%d%d%d",&n,&c,&k);
	len=c/k;
	for(int i=2;i<=n;i++)
	{
		scanf("%d",&a[i]);
		d[i-1]=a[i]-a[i-1];
	}
	d[n]=c-a[n];
	dfs(1,0,0);
	printf("No\n");
	return 0;
}

AC代碼

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e5;
int a[MAXN+5],fa[MAXN+5];
int n,c,k,len;
int Find(int x)
{
	return x==fa[x]?x:fa[x]=Find(fa[x]);
}
int main()
{
	scanf("%d%d%d",&n,&c,&k);
	len=c/k;
	for(int i=2;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=n;i++)
	{
		int j=lower_bound(a+1,a+n+1,(a[i]+len)%c)-a;
		if(j<=n&&a[j]==(a[i]+len)%c)
		{
			if(Find(i)==Find(j))
			{
				printf("Yes\n");
				return 0;
			}
			fa[Find(i)]=Find(j);		
		}
	}
	printf("No\n");
	return 0;
}

總結

我始終覺得自己的思路是可行的...只是不知道實現時哪裏出了問題...qwq.../執着

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章