[2027届]NOIP2024模拟赛#2

比赛链接

比昨天好多了,谢天谢地。

image

My rank : 4th。

好消息:明天放假。

坏消息:后天开学。

好消息:没暑假作业。

坏消息:拉了一堆课。

赛时

先写了T1暴力,然后一眼觉得正解是二进制位运算,所以先跑了。

T2题目给出了正解,照着打,过了 50pts,然后简单一想,过掉了。

T3写了暴力,先跑。

T4写了暴力,然后开始推性质,发现组合数,但是一直挂。

回过头看T3,发现正解写法,写了将近300行,但是到最后也没调出来,然后比赛就结束了。

总分:30+100+20+20=170。

T1

很容易发现题目上的 \(F\) 函数实际上就是 \(\log_2 (x \& -x)\),然后暴力赋值,有30pts。

对于正解,考虑二分第 \(k\) 大,\(check\) 函数的话考虑 \(F\) 函数的值只有 \(log\) 级别,对于前面的 \(n\),容易发现就是一个等差数列。

枚举 \(F\) 的取值,找到对于每个取值在查询的答案之下的数字的个数,加上等差数列,发现仍然单调,所以算法可行。

找到 \(k\) 以后,再去求每个取值中比他大的数字的和,分成两部分,等差数列直接通项公式, \(F\) 的话直接加。

然后做完了,复杂度 \(\mathcal{O}(T\log^2 V)\)

T2

本场最简单的题,谢谢老师开恩\gb\gb\gb\gb\gb\gb\gb\gb\gb\gb\gb。

前五十分写脸上了,不说了。

后五十分根据前面的情况考虑,容易发现题目所给的 SB-Tree 有一个左儿子<根<右儿子的性质,然后从根开始跑,比较大小决定当前走向即可。

注意分数比较大小要用乘号,否则会像某位军师一样爆精度。

T3

对于没有问号的情况,直接暴力。

思考正解,以当前想要保留 R 为例,我们把数列按照 R 为边界分成多个区间,判断每个 R 是否保留,DP即可。

赛时写了暴力和性质,但是性质写挂了,并且代码成了一大坨,下面给出赛时代码,慎看

点击查看代码
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<ext/pb_ds/trie_policy.hpp>
#include<ext/pb_ds/priority_queue.hpp>
#define int long long
using namespace std;
using namespace  __gnu_pbds;
//gp_hash_table<string,int>mp2;
//__gnu_pbds::priority_queue<int,less<int>,pairing_heap_tag> q;
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
inline int mul(int a,int b,int mod)
{
    int A=a*(b>>30ll)%mod*(1ll<<30)%mod;
    int B=a*(b&((1ll<<30)-1))%mod;
    return (A+B)%mod;
}
const int mod=998244353;
const int maxn=1e6+10;
bool can(char a,char b)
{
	if(a=='R'&&b=='P'||a=='P'&&b=='S'||a=='S'&&b=='R')return 0;
	return 1;
}
string s;
int n;
int ar,ap,as;
map<string,bool> mp;
void dfs(string s)
{
	bool f=1;
	for(int i=1;i<s.size();i++)if(s[i-1]!=s[i]){f=0;break;}
	if(f)
	{
		int m=s.size();
		if(s[0]=='R')ar=max(ar,m);
		else if(s[0]=='P')ap=max(ap,m);
		else if(s[0]=='S')as=max(as,m);
		return ;
	}
	if(mp[s])return ;
	mp[s]=1;
	for(int i=1;i<s.size();i++)
	{
		 if(s[i]==s[i-1])continue;
		 string t=s;
		 if(can(s[i-1],s[i]))s.erase(i,1);
		 else s.erase(i-1,1);
		 dfs(s);
		 s=t;
	}
}
int pos[maxn],tot,res=0;
int sumr[maxn],sump[maxn],sums[maxn];
char a[maxn];
struct no
{
	int l,r;
	bool f;
}x[maxn];int cnt=0;
void Subtask()
{
	for(int i=0;i<s.size();i++)a[i+1]=s[i];
	n=s.size();
	for(int i=1;i<=n;i++)
	{
		sumr[i]=sumr[i-1]+(a[i]=='R');
		sump[i]=sump[i-1]+(a[i]=='P');
		sums[i]=sums[i-1]+(a[i]=='S');
	}
	// R
	tot=0;cnt=0;
	res=0;
	pos[++tot]=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]=='R')pos[++tot]=i;
	}
	pos[++tot]=n+1;
	for(int i=2;i<=tot;i++)
	{
		int l=pos[i-1]+1,r=pos[i]-1;
		if(l>r)continue;
		x[++cnt]={l,r,0};
	}
	for(int i=1;i<=cnt;i++)
	{
		int l=x[i].l,r=x[i].r;
		if(sums[r]-sums[l-1]>0)
		{
			x[i].f=1;
			continue;
		}	
		int ll=i,rr=i,mi=1e9+7;;
		while(ll>0)
		{
			ll--;
			if(x[ll].f)
			{
				int nl=x[ll].r,nr=x[i].l;
				mi=min(mi,nr-nl-1);
			}
		}
	}
	int l=1e9+7,r=1e9+7,ma=0,sum=0;
	for(int i=1;i<=n;i++)
	{
		if(sums[i])l=min(l,i);
		if(sums[i]==sums[n])r=min(r,i);
	}
	for(int i=1;i<=n;i++)
	{
		if(a[i]=='S'||a[i]=='P')break;
		res++;
	}
	for(int i=n;i>=1;i--)
	{
		if(a[i]=='S'||a[i]=='P')break;
		res++;
	}
	for(int i=l;i<=r;i++)
	{
		if(a[i]=='S')
		{
			res+=ma;
			sum=ma=0;
		}
		else if(a[i]=='P')
		{
			sum=0;
		}
		else if(a[i]=='R')
		{
			sum++;
			ma=max(ma,sum);
		}
	}
    cout<<res<<endl;
    // S
	tot=0;cnt=0;
	res=0;
	pos[++tot]=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]=='S')pos[++tot]=i;
	}
	pos[++tot]=n+1;
	for(int i=2;i<=tot;i++)
	{
		int l=pos[i-1]+1,r=pos[i]-1;
		if(l>r)continue;
		x[++cnt]={l,r,0};
	}
	for(int i=1;i<=cnt;i++)
	{
		int l=x[i].l,r=x[i].r;
		if(sums[r]-sums[l-1]>0)
		{
			x[i].f=1;
			continue;
		}	
		int ll=i,rr=i,mi=1e9+7;;
		while(ll>0)
		{
			ll--;
			if(x[ll].f)
			{
				int nl=x[ll].r,nr=x[i].l;
				mi=min(mi,nr-nl-1);
			}
		}
	}
	l=1e9+7,r=1e9+7,ma=0,sum=0;
	for(int i=1;i<=n;i++)
	{
		if(sump[i])l=min(l,i);
		if(sump[i]==sump[n])r=min(r,i);
	}
	for(int i=1;i<=n;i++)
	{
		if(a[i]=='R'||a[i]=='P')break;
		res++;
	}
	for(int i=n;i>=1;i--)
	{
		if(a[i]=='R'||a[i]=='P')break;
		res++;
	}
	for(int i=l;i<=r;i++)
	{
		if(a[i]=='P')
		{
			res+=ma;
			sum=ma=0;
		}
		else if(a[i]=='R')
		{
			sum=0;
		}
		else if(a[i]=='S')
		{
			sum++;
			ma=max(ma,sum);
		}
	}
    cout<<res<<endl;
    // P
	tot=0;cnt=0;
	res=0;
	l=1e9+7,r=1e9+7;
	ma=0,sum=0;
	pos[++tot]=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]=='P')pos[++tot]=i;
	}
	pos[++tot]=n+1;
	for(int i=2;i<=tot;i++)
	{
		int l=pos[i-1]+1,r=pos[i]-1;
		if(l>r)continue;
		x[++cnt]={l,r,0};
	}
	for(int i=1;i<=cnt;i++)
	{
		int ll=i,rr=i,mi=1e9+7;;
		while(ll>0)
		{
			ll--;
			if(x[ll].f)
			{
				int nl=x[ll].r,nr=x[i].l;
				mi=min(mi,nr-nl-1);
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(sumr[i])l=min(l,i);
		if(sumr[i]==sumr[n])r=min(r,i);
	}
	for(int i=1;i<=n;i++)
	{
		if(a[i]=='S'||a[i]=='R')break;
		res++;
	}
	for(int i=n;i>=1;i--)
	{
		if(a[i]=='S'||a[i]=='R')break;
		res++;
	}
	for(int i=l;i<=r;i++)
	{
		if(a[i]=='R')
		{
			res+=ma;
			sum=ma=0;
		}
		else if(a[i]=='S')
		{
			sum=0;
		}
		else if(a[i]=='P')
		{
			sum++;
			ma=max(ma,sum);
		}
	}
    cout<<res<<endl;
}
signed main()
{
	freopen("rps.in","r",stdin);
	freopen("rps.out","w",stdout);
	cin>>s;
	n=s.size();
	if(n<=11){dfs(s);printf("%lld\n%lld\n%lld\n",ar,ap,as);return 0;}
	bool Sub=1;
	for(int i=0;i<n;i++){if(s[i]=='?')Sub=0;break;}
	if(Sub){Subtask();return 0;} 
	return 0;
}
//RPSRPSRPSRS

T4

赛时写了暴力,有20pts。

去研究一下 \(a=0\) 的性质,发现和组合数有关,推了一会发现推不下去了。

对于正解,考虑状压。

裸的有50pts,但是优化的话严格超纲,所以不写了。

总结

啦啦啦。

posted @ 2024-08-02 13:16  Redamancy_Lydic  阅读(19)  评论(0编辑  收藏  举报