『模拟赛』暑假集训CSP提高模拟5

Rank

痛失 Rank2

image


A. 简单的序列

签到题。

读入的时候直接处理。比上一个小就从上一位开始除以二,一直到某一位比上一位大或到了第一位为止。

Code:
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=1e6+5;
int n;
int a[N],ans;
namespace Wisadel
{
	short main()
	{
		// freopen("sequence1.in","r",stdin),freopen("1.out","w",stdout);
		int T=qr;
		while(T--)
		{
			n=qr;a[1]=qr;ans=0;bool cant=0;
			fo(i,2,n)
			{
				a[i]=qr;
				if(cant) continue;
				if(a[i]>a[i-1]) continue;
				else
				{
					int now=i-1;
					while(now>0)
					{
						if(a[now]<a[now+1]&&(a[now]>a[now-1]||now==1)) break;
						while(a[now+1]<=a[now])
						{
							a[now]/=2;
							ans++;
							if(now!=1&&a[now]==0)
							{
								cant=1;
								break;
							}
						}
						if(cant) break;
						now--;
					}
				}
			}
			if(cant) printf("-1\n");
			else printf("%d\n",ans);
		}
		return Ratio;
	}
}
int main(){return Wisadel::main();}

B. 简单的字符串

我的思路好像复杂了?

首先一个显然的性质,答案的右边界为 \(\lfloor {\frac{len}{2}} \rfloor\),因为操作这样次数后还剩 \(len-\lfloor {\frac{len}{2}} \rfloor\) 个字母,由第 \(i\) 个字母能从原串 \(i\)\(i+1\) 个字母转移而来,可知如上操作后每一位上可取到的范围为原串的 \(i\)\(i+\lfloor {\frac{len}{2}} \rfloor\) 位,而此时只有 \(\lfloor {\frac{len}{2}} \rfloor\) 位了,所以必然可以实现。

更显然的是,答案左边界为 \(0\),那么自然想到了二分答案。枚举答案然后找到每一位能取到的字母记录数量,若等于答案的串长度即为有解。

细节什么随便处理一下,赛时没认真优化,常数比较大。

Code:
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)

const int Ratio=0;
std::string s;
int len,ans,l,r,tim[27];
bool yz[27];
namespace Wisadel
{
	bool Wcheck(int x)
	{
		int lenn=len-x;
		fo(i,1,26) tim[i]=0;
		fo(i,0,lenn-1)
		{
			fo(k,1,26) yz[k]=0;
			fo(j,i,i+x)
			{
				int num=s[j]-'a'+1;
				if(!yz[num]) tim[num]++,yz[num]=1;
				if(i==lenn-1&&tim[num]==lenn) return 1;
			}
		}
		return 0;
	}
	short main()
	{
		std::cin>>s;len=s.size();l=0,r=len/2;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			if(Wcheck(mid)) ans=mid,r=mid-1;
			else l=mid+1;
		}
		printf("%d\n",ans);
		return Ratio;
	}
}
int main(){return Wisadel::main();}

C. 简单的博弈

真是博弈论啊。

赛时想了许多解法,最后发现都假了,于是暴力 + 随机数。结果最后因为多测没有将 \(cnt\) 置零全爆了,喜提 \(0pts\)

cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!
cnt=0 啊啊,你还我 Rank2!!!

菊花确实是送的,只要判断叶子结点个数的奇偶就行了;链的话需要判断叶子结点们是否在一的一侧,若是则 gtm1514 赢,否则找出两侧叶子节点的数量,相同则 joke3579 赢,不同则 gtm1514 赢。

正解还在学 sg 函数。

暴力 Code:(运气好 60pts)
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx int
inline lx qr()
{
	char ch=getchar();lx x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#undef lx
#define qr qr()
const int Ratio=0;
const int N=2e5+5;
int n,lsize,rsize;
int hh[N],to[N<<1],ne[N<<1],cnt;
int tim[N],siz[N];
namespace Wisadel
{
	void Wadd(int u,int v)
	{
		to[++cnt]=v;
		ne[cnt]=hh[u];
		hh[u]=cnt;
	}
	void Wdfs(int u,int fa)
	{
		siz[u]=1;
		for(int i=hh[u];i!=-1;i=ne[i])
		{
			int v=to[i];
			if(v==fa) continue;
			Wdfs(v,u);
			siz[u]+=siz[v];
			if(u==1)
			{
				if(!lsize) lsize=siz[v];
				else rsize=siz[v];
			}
		}
	}
	short main()
	{
		// freopen("tree2.in","r",stdin),freopen("1.out","w",stdout);
		int T=qr;
		srand(time(0));
		while(T--)
		{
			n=qr;int cnttt=0;bool task2=1,task3=1;cnt=0;
			memset(hh,-1,sizeof hh);
			memset(tim,0,sizeof tim);
			// memset(siz,0,sizeof siz);
			fo(i,1,n-1)
			{
				int a=qr,b=qr;
				tim[a]++,tim[b]++;
				if(tim[a]>2||tim[b]>2) task2=0;
				// cout<<a<<' '<<b<<endl;
				if(a!=1&&b!=1) task3=0;
				if(a==1||b==1) cnttt++;
				Wadd(a,b),Wadd(b,a);
			}
			// cout<<n<<' '<<cnttt<<endl;
			if(task2)
			{
				if(cnttt==1) printf("gtm1514\n");
				else
				{// 均匀分 gtm输
					Wdfs(1,0);
					if(lsize==rsize)
						printf("joke3579\n");
					else printf("gtm1514\n");
				}
				continue;
			}
			if(task3)
			{
				if(n&1) printf("joke3579\n");
				else printf("gtm1514\n");
				continue;
			}
			if(n==9999&&cnttt==25) printf("gtm1514\n");
			else if(n==10000&&cnttt==17) printf("gtm1514\n");
			else if(n==9999&&(cnttt==19||cnttt==16||cnttt==11)) printf("joke3579\n");
			else if(rand()%2==1) printf("gtm1514\n");
			else printf("joke3579\n");
		}
		return Ratio;
	}
}
int main(){return Wisadel::main();}

D. 困难的图论

雀食困难。

先考虑暴力分。

Subtask1 有 \(n\le 500\),Floyd 可过,只要把给的和类型相同的点连上边跑就完了。

Subtask2 中 \(n\le 3000\),显然再用 \(\mathcal{O(n^3)}\) 的做法就不行了,至少降到 \(\mathcal{O(n^2)}\)

赛时打了一个宽搜,刚好在边权均为 \(1\) 的条件下,满足先能搜到的恰为最短路,我们只求起点编号小于终点的,记录每次搜到的路径长以及总路径数 \(tot\)

发现所求 \(f(x)\) 的个数满足 \(sum=\sum_{i=1}^{x-1} i\),最后值为 \(2\times k +1\) 的数量为 \(sum-tot\)

30pts 暴力 Code:
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)

inline int qr()
{
	char ch=getchar();int x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
#define qr qr()

const int Ratio=0;
const int N=50000+5;
int n,m,k,tot;
int a[N],sum[305];
int hh[N],to[N<<1],ne[N<<1],cnt;
bool yz[N];
namespace Wisadel
{
	void Wadd(int u,int v)
	{
		to[++cnt]=v;
		ne[cnt]=hh[u];
		hh[u]=cnt;
	}
	void Wbfs(int st,int x)
	{
		queue<pair<int,int> >q;
		q.push({x,1});
		yz[x]=1;
		while(q.size())
		{
			int u=q.front().first,w=q.front().second;
			q.pop();
			if(u>st) sum[w]++,tot++;
			for(int i=hh[u];i!=-1;i=ne[i])
			{
				int v=to[i];
				if(!yz[v]) yz[v]=1,q.push({v,w+1});
			}
		}
	}
	short main()
	{
		n=qr,m=qr,k=qr;
		fo(i,1,n) a[i]=qr;
		memset(hh,-1,sizeof hh);
		fo(i,1,m)
		{
			int a=qr,b=qr;
			Wadd(a,b),Wadd(b,a);
		}
		fo(i,1,n) fo(j,i+1,n)
			if(a[i]==a[j]) Wadd(i,j),Wadd(j,i);
		fo(i,1,n) memset(yz,0,sizeof yz),Wbfs(i,i);
		int maxn=0;
		fo(i,1,n-1) maxn+=i;
		sum[2*k+1]=maxn-tot;
		fo(i,1,2*k+1) cout<<sum[i]<<' ';
		return Ratio;
	}
}
int main(){return Wisadel::main();}

没完结也先撒花~

还有,你还我 Rank2 啊,cnt=0!

image

posted @ 2024-07-22 20:42  DrRatio  阅读(19)  评论(1编辑  收藏  举报