加载中…

返回上一页

NOIP模拟2

下发文件

将军棋

又一道交互题.

发现这个无特殊性质的数据它的 Q 的使用次数较多,说明这道题需要继续按数据点编程.

特殊性质 A

扫一遍,每次找到相邻两个位置有不同的时 cnt + 1.

rll cnt=1;
if(t>=1&&t<=15)
{
	g.emplace_back(1);
	for(rll i=2;i<=n;i++) if(query(i-1,i)==2) g.emplace_back(++cnt); else g.emplace_back(cnt);
	return g;
}

特殊性质 B

从当前位置往前找,每次找到有新的种类出现时,进行一次 check,如果数量和不算上该点一样的话说明就是这个类型. 否则继续找到下一个类型出现的位置.

if(t>=16&&t<=34)
{
	g.emplace_back(1);
	for(rll i=2;i<=n;i++)
	{
		rg bool flag[4]={0};
		for(rll j=i-1;j;j--)
		{
			if(j==1||g[j-1]!=g[j-2]&&(!flag[g[j-1]])) 
			{ 
				flag[g[j-1]]=1; rll cnt=(ll)flag[1]+flag[2]+flag[3]; if(query(j,i)==cnt) { g.emplace_back(g[j-1]);break; }
			}
			if((ll)flag[1]+flag[2]+flag[3]==2) { if(!flag[1]) g.emplace_back(1); else if(!flag[2]) g.emplace_back(2); else g.emplace_back(3); break; }
			if(j==1) { if(!flag[2]) g.emplace_back(2); else g.emplace_back(3); }
		}
	}
	return g;
}

特殊性质 C

可能是这些里面最难的了.

按照和 B 的方法找,最多会找 3000 次,超出这个范围. 所以需要修改一下,将其进行一个伪的二分,这样每次最多查询两个.

if(t>=35&&t<=48)
{
	g.emplace_back(1); ls[1]=1; rll p[5]={0,1,2,3,4};
	for(rll i=2;i<=n;i++)
	{
		sort(p+1,p+5,cmp);
		if((!ls[p[2]])||query(ls[p[2]],i)<=2) { if(query(ls[p[1]],i)==1) g.emplace_back(p[1]); else g.emplace_back(p[2]); }
		else { if((!ls[p[3]])||query(ls[p[3]],i)==3) g.emplace_back(p[3]); else g.emplace_back(p[4]); }
		ls[g.back()]=i;
	}
	return g;
}

特殊性质 D

只需要扫一遍找到大小突然变化的地方,再扫一遍确定两个点的位置.

if(t>=49&&t<=60)
{
	if(query(1,n)==n) { for(rll i=1;i<=n;i++) g.emplace_back(i); return g; }
	for(rll i=2;i<=n;i++) if(query(1,i)^i) {
		for(rll j=2;j<=i;j++) if(query(j,i)==i-j+1)
		{ 
			j--; for(rll k=1;k<=n;k++) if(k==i) g.emplace_back(j); else if(k>i) g.emplace_back(k-1); else g.emplace_back(k);
			break;
		}
		break;
	}
	return g;
}

无特殊性质

将每一个点,它的前面进行二分,找出在这个数之前出现的那一个值.

g.emplace_back(1);a[1][1]=1;
for(rll i=2,l,r,mid,ans;i<=n;i++)
{
	a[1][i]=query(1,i);if(a[1][i]==a[1][i-1]+1) { g.emplace_back(++cnt); for(rll j=2;j<=i;j++) a[j][i]=a[j][i-1]+1; continue; }
	l=1,r=i-1,ans=0; while(l<=r)
	{ 
		mid=(l+r)>>1; 
		// cout<<mid<<' '<<i<<' '<<query(mid,i)<<' '<<a[mid][i-1]<<endl;
		if(query(mid,i)==a[mid][i-1]) ans=mid,l=mid+1; else r=mid-1; 
	}
	ans=g[ans-1]; memset(sum,0,sizeof(sum)); g.emplace_back(ans);
	for(rll j=i,tot=0;j>1;j--) { if(!sum[g[j-1]]) tot++; sum[g[j-1]]=1;a[j][i]=tot;/*cout<<j<<' '<<i<<' '<<tot<<endl;*/ }
}
// for(rll i=0;i<g.size();i++) write(g[i]),put_;putn;
return g;

代码部分可能在编辑时有缺少部分符号,不影响理解. 如有也请留言,我会第一时间修改.

记住交互题里多余的函数一定要删掉!删掉!删掉! 因为 read() 函数名重复 CE 爆了 86 分.

小明的变换

发现一个很有趣的规律:把每一个数不断往后放,和先移前面再移后面,抑或是先移后面再移前面,这样最终都能够达到一样的序列.

所以,每次找到第一处不相同的或是数目不一样的.

找到不相同的就将它不断向后面移,如果移不了(后面没有这个数了)就是无解.

数目不一样的话就记录一下缺多少,然后再向后面要. 中间的部分还是按照不同的处理.

如果多了,就把多余的部分按照不同的处理.

具体的还需要预处理一个前缀和,代表每一串连续的数有多少个. 每次直接跳到这一相同数段的最后一个位置即可.

就这玩意我还调了一个多小时

点击查看代码
#include<bits/extc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 1000001
#define pll pair<ll,ll>
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll t,n,c[maxn],d[maxn],nx[maxn];
vector<pll> a,b;
__gnu_pbds::gp_hash_table<ll,ll> mp;
bool fl;
int main()
{
	freopen("trans.in","r",stdin); freopen("trans.out","w",stdout);
	t=read(); for(rll k=1;k<=t;k++)
	{
		a.clear();b.clear(); n=read(); for(rll i=1;i<=n;i++) c[i]=read(); for(rll i=1;i<=n;i++) d[i]=read(); 
		a.emplace_back(0,0);b.emplace_back(0,0); mp.clear(); c[n+1]=d[n+1]=0;
		// if(k==31) {for(rll i=1;i<=n;i++) write(c[i]),put_;putn;for(rll i=1;i<=n;i++) write(d[i]),put_;putn;}
		fl=0; for(rll i=1;i<=n;i++) if(c[i]^d[i]) { fl=1;break; } if(!fl) { puts("Yes"); continue; }
		for(rll i=n;i;i--) if(c[i]^c[i+1]) { if(mp[c[i]]) nx[i]=mp[c[i]]; else nx[i]=0; mp[c[i]]=i; }
		for(rll i=1,cnt=0;i<=n;i++) { if(c[i]==c[i-1]) cnt++; else cnt=1; a.emplace_back(c[i],cnt); }
		for(rll i=1,cnt=0;i<=n;i++) { if(d[i]==d[i-1]) cnt++; else cnt=1; b.emplace_back(d[i],cnt); }
		fl=0; sort(c+1,c+n+1);sort(d+1,d+n+1); for(rll i=1;i<=n;i++) if(c[i]^d[i]) { fl=1;break; } if(fl) { puts("No"); continue; }
		for(rll i=1,j=1;i<=n&&j<=n;i++,j++)
		{
			// cout<<"00\n";
			while(b[j].first==b[j+1].first) j++;
			// for(rll i=1;i<=n;i++) cout<<a[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<a[i].second<<' ';cout<<endl;
			// for(rll i=1;i<=n;i++) cout<<b[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<b[i].second<<' ';cout<<endl; 
			// cout<<'#'<<i<<' '<<j<<endl;
			// puts("Continue...");getchar();
			rll cnt=0;
			while(cnt<b[j].second)
			{
				while(a[i].first==a[i+1].first) i++;
				if(a[i].first==b[j].first&&a[i].second+cnt==b[j].second) break;
				if(a[i].first==b[j].first) 
				{ 
					if(a[i].second>=(b[j].second-cnt)) 
					{
						if(a[i].second>(b[j].second-cnt)&&(!nx[i])) 
						{
							// cout<<"*0 "<<i<<' '<<j<<' '<<a[i].first<<' '<<a[i].second<<' '<<b[j].second<<' '<<cnt<<endl; 
							// for(rll i=1;i<=n;i++) cout<<a[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<a[i].second<<' ';cout<<endl;
							// for(rll i=1;i<=n;i++) cout<<b[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<b[i].second<<' ';cout<<endl; 
							fl=1;break; 
						}
						// cout<<"*1 "<<i<<' '<<j<<' '<<a[i].first<<' '<<a[i].second<<' '<<b[j].second<<' '<<cnt<<endl; 
						a[nx[i]].second+=a[i].second-(b[j].second-cnt);a[i].second=(b[j].second-cnt);
						// for(rll i=1;i<=n;i++) cout<<a[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<a[i].second<<' ';cout<<endl;
						// for(rll i=1;i<=n;i++) cout<<b[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<b[i].second<<' ';cout<<endl;
						break;
					}
					else 
					{
						// cout<<"*2 "<<i<<' '<<j<<' '<<a[i].first<<' '<<a[i].second<<' '<<b[j].second<<' '<<cnt<<endl;
						cnt+=a[i].second,a[i].second=0,i++;
						// for(rll i=1;i<=n;i++) cout<<a[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<a[i].second<<' ';cout<<endl;
						// for(rll i=1;i<=n;i++) cout<<b[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<b[i].second<<' ';cout<<endl;
					}
				}
				else
				{
					if(!nx[i])
					{ 
						// cout<<"*3 "<<i<<' '<<j<<' '<<a[i].first<<' '<<a[i].second<<' '<<b[j].second<<' '<<cnt<<endl;
						// for(rll i=1;i<=n;i++) cout<<a[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<a[i].second<<' ';cout<<endl;
						// for(rll i=1;i<=n;i++) cout<<b[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<b[i].second<<' ';cout<<endl; 
						fl=1;break;
					}
					a[nx[i]].second+=a[i].second;a[i].second=0;i++;
					// cout<<"*4 "<<i<<' '<<j<<' '<<a[i].first<<' '<<a[i].second<<' '<<b[j].second<<' '<<cnt<<endl;
					// for(rll i=1;i<=n;i++) cout<<a[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<a[i].second<<' ';cout<<endl;
					// for(rll i=1;i<=n;i++) cout<<b[i].first<<' ';cout<<endl;for(rll i=1;i<=n;i++) cout<<b[i].second<<' ';cout<<endl; 
				}
				if(i>n) { /*cout<<"-1\n";*/fl=1;break; }
			}
			if(fl) break;
		}
		puts(fl?"NO":"YES");
	}
	return 0;
}

小明过生日

容易发现,一个合法的序列只有在两端是奇数中间是偶数时才可以.

为什么呢?可以考虑:一个奇数长的段会导致错位,只有错开一位才能够将这一段回文变成一个唯一可能的段(就是全部是同一个字母).

所以,如果多于两个奇数,一定不合法. 否则,把奇数单独拎出来,一个放在前面,如果有另一个就放在最后面(因为一个奇数只会改变它后面所有数的错位状态).

m = 1 时,特判一下,把它一个和分解为两个的情况输出(当然还要再特判 n = 1的情况).

点击查看代码
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define pll pair<ll,ll>
#define maxn 1001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
	rg bool f=0;rll x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar(); return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10);putchar(x%10|'0'); }
ll n,m,cnt,a[maxn];
vector<ll> b;
inline bool cmp(rll x,rll y) { return (x&1)>(y&1); }
int main()
{
	freopen("birth.in","r",stdin); freopen("birth.out","w",stdout);
	n=read();m=read(); for(rll i=1;i<=m;i++) cnt+=(a[i]=read())&1;// ,cout<<cnt<<endl;
	if(cnt>2) { puts("-1"); return 0; }
	if(m==1) { if(a[1]==1) puts("1\n1\n1"); else write(a[1]),putn,write(2),putn,write(a[1]-1),put_,putchar('1'); return 0; }
	sort(a+1,a+m+1,cmp);write(a[1]),put_; for(rll i=3;i<=m;i++) write(a[i]),put_; write(a[2]);putn;
	b.emplace_back(a[1]+1); for(rll i=3;i<=m;i++) b.emplace_back(a[i]); if(a[2]^1) b.emplace_back(a[2]-1);
	write(b.size());putn;for(rll i=0;i<b.size();i++) write(b[i]),put_;
	return 0;
}

小明爱数数

原题:CF1608F.

显然大神说的要比我这个蒟蒻说的详细,就不想写了. 以后有时间再认真写一遍(估计可能没有,有也忘了

posted @ 2022-11-10 19:04  1Liu  阅读(7)  评论(0编辑  收藏  举报