gym102460I The Spectrum 2019ICPC Taipei

https://codeforces.com/gym/102460

曾今OI时期还是搜索king,打了acm以后没有搜索骗分了,弱智搜索题都不会写了

dfs(k,l,r)表示每次取出一个剩下还没确定最大的差值num[k],当前已经确定了1-l和r-n的值,且这些数之间两两只差都已经算过了,那么剩下的最大值一定是a[r-1]-a[1]或者a[n]-a[l+1],那么这个搜索的最坏复杂度就是2^62次方的,但是这题是要输出所有方案的,说明合法方案其实并不多,所以可以加一些剪枝优化。

首先考虑如果当前已经确定的数字组成的某些差值已经超过了给出的总数,这个是合法性剪枝,然而对这题是完全不够的。

考虑第一个样例的等差数列情况,这时你无论怎么选,最后造出来的序列都是一样的,就会变成2^62跑满,所以我们对于dfs(k,l,r)做一个记忆化,1-l,r-n这些已经确定的数字如果之前已经搜索过的话,就不需要再进行搜索,等差数列的情况就可以被大大减少,状态总数就只有n*n也就是dfs(k,l=1-n,r=l+1-n)

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
typedef unsigned long long ull;

const int maxl=4010;

int n,m;
int num[maxl],a[maxl],now[maxl],cnt[maxl];
vector<vector<int>> ans;
unordered_map<ull,bool> mp; 
ull mi[maxl];
vector<int> tmp;

inline void prework()
{
	scanf("%d",&n);
	mi[0]=1;
	for(int i=1;i<=n;i++)
		mi[i]=mi[i-1]*1009;
	m=n*(n-1)/2;
	for(int i=1;i<=m;i++)
		scanf("%d",&num[i]),++cnt[num[i]];
	sort(num+1,num+1+m);
}

inline ull geths(int l,int r)
{
	ull ret=0;
	for(int i=1;i<=l;i++)
		ret+=a[i]*mi[i];
	for(int i=r;i<=n;i++)
		ret+=a[i]*mi[i];
	return ret;
}

inline void dfs(int k,int l,int r)
{
	if(l+1==r)
	{
		tmp.clear();
		for(int i=1;i<=n;i++)
			tmp.pb(a[i]);
		ans.pb(tmp);
		return;
	}
	while(now[num[k]]==cnt[num[k]] && k>0)
		--k;
	ull hs=geths(l,r);
	if(mp[hs])
		return;
	mp[hs]=true;
	bool flag;
	if(num[k]<a[r])
	{
		a[r-1]=num[k];flag=true;
		for(int i=1;i<=l;i++)
		if(++now[a[r-1]-a[i]]>cnt[a[r-1]-a[i]])
			flag=false;
		for(int i=r;i<=n;i++)
		if(++now[a[i]-a[r-1]]>cnt[a[i]-a[r-1]])
			flag=false;
		if(flag)
			dfs(k-1,l,r-1);
		for(int i=1;i<=l;i++)
			--now[a[r-1]-a[i]];
		for(int i=r;i<=n;i++)
			--now[a[i]-a[r-1]];
		a[r-1]=0;
	}
	if(a[n]-num[k]>a[l])
	{
		a[l+1]=a[n]-num[k];flag=true;
		for(int i=1;i<=l;i++)
		if(++now[a[l+1]-a[i]]>cnt[a[l+1]-a[i]])
			flag=false;
		for(int i=r;i<=n;i++)
		if(++now[a[i]-a[l+1]]>cnt[a[i]-a[l+1]])
			flag=false;
		if(flag)
			dfs(k-1,l+1,r);
		for(int i=1;i<=l;i++)
			--now[a[l+1]-a[i]];
		for(int i=r;i<=n;i++)
			--now[a[i]-a[l+1]];
		a[l+1]=0;
	}
	 
}

inline void mainwork()
{
	if(a[m]>999) return;
	if(n==2)
	{
		tmp.clear();tmp.pb(0);tmp.pb(a[1]);
		ans.pb(tmp);
		return;
	}
	a[1]=0;a[n]=num[m];
	++now[num[m]];
	dfs(m-1,1,n);
}

inline bool cmp(const vector<int> &a,const vector<int> &b)
{
	for(int i=0;i<n;i++)
	if(a[i]<b[i])
		return true;
	else if(a[i]>b[i]) 
		return false;
	return true;
}

inline void print()
{
	sort(ans.begin(),ans.end(),cmp);
	ans.erase(unique(ans.begin(),ans.end()),ans.end());
	printf("%d\n",(int)ans.size());
	for(auto d:ans)
		for(int j=0;j<=n-1;j++)
			printf("%d%c",d[j]," \n"[j==n-1]);
}

int main()
{
	//freopen("I.in","r",stdin);
	prework();
	mainwork();
	print();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/108533262