Codeforces Round #610 Div2

1282D Enchanted Artifact(构造 贪心 交互)

题意:

​ 你需要猜一个长度为n且仅由a和b组成的密文S,你可以向系统询问信息,每次询问输出一个非空串T,系统将告诉你(输入)S和T之间的编辑距离,你必须在n+2次询问内猜中密文S。S和T之间的编辑距离定义为:对S进行的最小操作数(对单个字符进行替换插入删除),使S=T ( 1 ≤ n ≤ 300 ) (1\le n\le300) (1n300)

解法:

​ 有意思的交互题。由于n不超过300,我们第一次询问串 T a = a a . . . a a , ∣ T a ∣ = 300 T_a=aa...aa,|T_a|=300 Ta=aa...aa,Ta=300,设系统返回的值为ax,则S中字符a的个数一定为300-ax;同理,第二次询问串 T b = b b . . . b b , ∣ T b ∣ = 300 T_b=bb...bb,|T_b|=300 Tb=bb...bb,Tb=300,设系统返回bx,则S中字符b的个数为300-bx,所以得到答案串长度n为600-ax-bx。于是分别用变量 c n t a 、 c n t b cnta、cntb cntacntb记录答案串中字符a和b的个数,并且初始化串 T 0 = a a . . . a a , ∣ T 0 ∣ = n T_0=aa...aa,|T_0|=n T0=aa...aa,T0=n。然后进行n-1次询问,第i次询问将 T 0 T_0 T0中的第i个字符改为b,并比较本次返回值ans和上一次询问的返回值las(初始化为cntb):若 a n s < l a s ansans<las,说明答案串第i个字符正是b,则cntb–,las=ans;否则说明第i个字符为a,因此将该字符改回a,且cnta–。最后根据cnta或cntb判断第n个字符,最后一次询问输出答案即可(由于一共只能询问n+2次,最后一次询问的内容必须是答案串)。

​ 复杂度: O ( n 2 ) O(n^2) O(n2)

#include
#define ll long long
using namespace std;
string sets(char c,int len)
{
	string ans="";
	while(len--) ans+=c;
	return ans;
}
int query(string s)
{
	cout<<s<<endl;
	int x; cin>>x;
	if(!x) exit(0);
	return x;
}
int main()
{
	int cnta=300-query(sets('a',300));
	int cntb=300-query(sets('b',300));
	int n=cnta+cntb,las=cntb;
	string s=sets('a',n);
	for(int i=0;i<n-1;i++)
	{
		s[i]='b';
		int ans=query(s);
		if(ans<las) las=ans,cntb--;
		else s[i]='a',cnta--;
	}
	if(cntb) s[n-1]='b';
	query(s);
}

1282E The Cake Is a Lie(图论 搜索 拓扑排序)

题意:

​ 给一个n边形蛋糕,你需要切n-3次,切出n-2块三角形蛋糕,每次需要沿两端点将蛋糕切成两部分,其中的一块蛋糕必须为三角形并将其拿走。蛋糕的n个端点已有1~n的编号,最终的三角形蛋糕也有1~n-2的编号,按编号顺序给出每个三角形蛋糕的三个端点对应的编号,求:1. 原蛋糕的n个端点的顺序编号,顺时针或逆时针均可;2. 按切蛋糕的顺序,每次拿走的三角形蛋糕编号 ( 3 ≤ n ≤ 1 0 5 ) (3\le n\le 10^5) (3n105)

解法:

​ 设一块三角形蛋糕的三个端点为一个三元组{u,v,w},经观察可发现一个重要性质:与u、v同在一个三元组的w不会超过两个,且若这样的w只有一个,则端点u、v连成的线段一定在原蛋糕的边界线上;否则一定是蛋糕内部的分界线

​ 根据以上分析考虑两个问题。对于问题1,相当于要找到原蛋糕所有边界线,并形成一个圈,在圈上dfs顺序输出编号即可。对于问题2,将每一块三角形蛋糕看作结点,若两块蛋糕之间有一条分界线,即两个三元组中包含相同的u和v,则将两块蛋糕对应结点连边,问题即转换为该图的拓扑排序

​ 复杂度: O ( n ) O(n) O(n)

#include
#define ll long long
using namespace std;
const int maxn=1e5+5;
struct node
{
	int u,v;
	node(int ux,int vx)
	{	if(ux>vx) swap(ux,vx); u=ux,v=vx; }
};
int s,cnt,idx,deg[maxn],vis[maxn];
vector<node>id;
vector<int>e[2][maxn],v[maxn*3];
queue<int>q;
bool operator <(const node& x,const node& y)
{	return x.u<y.u||(x.u==y.u&&x.v<y.v); }
void link(int u,int v,int x)
{	e[x][u].push_back(v),e[x][v].push_back(u); }
void dfs(int u)
{
	if(vis[u]) return;
	vis[u]=true;
	cout<<u<<" ";
	for(int v:e[0][u]) dfs(v);
}
void bfs()
{
	while(!q.empty())
	{
		int u=q.front();
		q.pop(),vis[u]=true;
		cout<<u<<" ";
		for(int v:e[1][u])
		{
			if(vis[v]) continue;
			if(--deg[v]<=1) q.push(v),vis[v]=true;
		}
	}
}
int main()
{
	int t,n,x[3];
	cin>>t;
	while(t--)
	{
		cin>>n;
		map<node,int>mp;
		memset(deg,0,sizeof(deg));
		for(int i=1;i<=n-2;i++)
		{
			for(int j=0;j<3;j++) cin>>x[j];
			for(int j=0;j<3;j++)
			{
				node tmp=node(x[j],x[(j+1)%3]);
				if(!mp.count(tmp)) 
					id.push_back(tmp),idx=cnt++,mp[tmp]=idx;
				idx=mp[tmp];
				v[idx].push_back(i);
			}
		}
		for(int i=1;i<=n;i++)
			e[0][i].clear(),e[1][i].clear();
		for(int i=0;i<(int)id.size();i++)
			if(v[i].size()==1) link(id[i].u,id[i].v,0);
			else
			{
				link(v[i][0],v[i][1],1);
				deg[v[i][0]]++,deg[v[i][1]]++;
			} 
		memset(vis,0,sizeof(vis)),dfs(1),puts("");
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=n-2;i++)
			if(deg[i]==1) q.push(i),vis[i]=true;
		if(n==3) cout<<1; 
		bfs(),puts("");
		for(int i=0;i<cnt;i++) v[i].clear();
		cnt=0,id.clear();
	}
}

你可能感兴趣的:(CF补题记)