NOIP 模拟赛 #20

已经好久没写模拟赛题解了啊。。。

A. 邻间的骰子之舞

一个结论,可以打表,每一次复制后跟的粘贴数量要尽量相同,差不超过1,所以枚举复制了几次,然后二分最大的出来答案小于 \(n\) 的数 \(mid\),然后枚举多少个复制后的粘贴数为 \(mid+1\),出来的答案可以 \(O(1)\) 算,大于 \(n\) 直接输出就好了。

点击查看代码


#include<bits/stdc++.h>
#define int __int128
const int maxn=255;
using namespace std;
int n,x,y,tot,ans;

bool check(int x,int f)
{
	int temp=1;
	for(int i=1;i<=f;i++)
	{
		temp*=x;
		if(temp>n) return 1;
	}
	return 0;
}

int solve(int f)
{
	int l=0,r=n,ans=0;
	while(l<=r)
	{
		int mid=l+r>>1;
		if(check(mid+1,f)) ans=mid,r=mid-1;
		else l=mid+1; 
	}
	return ans;
}

template<typename T> inline T read() {
  T X = 0; bool flag = 1; char ch = getchar();
  while (ch < '0' || ch > '9') {if (ch == '-') flag = 0; ch = getchar();}
  while (ch >= '0' && ch <= '9') {X = (X << 1) + (X << 3) + ch - '0'; ch = getchar();}
  if (flag) return X;
  return ~ (X - 1);
}

template<typename T> inline void write(T X) {
  if (X < 0) {putchar('-'); X = ~ (X - 1);}
  int s[50], top = 0;
  while (X) {s[++top] = X % 10; X /= 10;}
  if (!top) s[++top] = 0;
  while (top) putchar(s[top--] + '0');
  puts("");
  return;
}

signed main()
{
	freopen("dice.in","r",stdin);
	freopen("dice.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	n=read<int>(),x=read<int>(),y=read<int>();
	tot=64;
	ans=x+y*n;
	for(int i=2,temp=0;i<=tot;i++)
	{
		int m=solve(i),flag=0;
		for(int j=0;j<=i;j++)
		{
			int temp=1;
			for(int k=1;k<=j;k++)
			{
				temp*=(m+1);
				if(temp>n)
				{
					flag=1;
					break;
				}
			}
			for(int k=1;k<=i-j;k++)
			{
				if(flag) break;
				temp*=m;
				if(temp>n)
				{
					flag=1;
					break;
				}
			}
			if(flag)
			{
				ans=min(i*x+i*(m-1)*y+j*y,ans);
				// cout<<i<<" "<<m<<" "<<j<<" "<<ans<<endl;
				break;
			}
		}
	}
	write(ans);

	return 0;
}
/*

*/

B. 星海浮沉录

水数据结构都不会了。。。,转化题意,维护每一个数的相邻出现位置的距离,找到最小的距离大于 \(x\) 的数,用 \(multiset\) 维护距离差,用线段树维护每个数的最大距离,复杂度 \(O((n+q)logn)\)

点击查看代码


#include<bits/stdc++.h>
#define lid id<<1
#define rid id<<1|1
#define mid (l+r>>1)
const int maxn=5e5+10;
using namespace std;
int n,q,a[maxn],G[maxn<<2],pos[maxn];
vector<int> l[maxn];
multiset<int> s[maxn];

void up(int id){G[id]=max(G[lid],G[rid]);}

void build(int id,int l,int r)
{
	if(l==r) return G[id]=s[l].size()?*(--s[l].end()):0,void(0);
	build(lid,l,mid),build(rid,mid+1,r); up(id);
}

void update(int id,int l,int r,int x)
{
	if(l==r) return G[id]=s[l].size()?*(--s[l].end()):0,void(0);
	x<=mid?update(lid,l,mid,x):update(rid,mid+1,r,x); up(id);
}

int query(int id,int l,int r,int x)
{
	if(l==r) return l;
	return G[lid]>x?query(lid,l,mid,x):query(rid,mid+1,r,x);
}

int main()
{
	freopen("star.in","r",stdin);
	freopen("star.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>q;
	for(int i=0;i<=n;i++) l[i].push_back(0);
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		l[a[i]].push_back(i);
		pos[i]=l[a[i]].size()-1;
	}
	for(int i=0;i<=n;i++) l[i].push_back(n+1);
	for(int i=0;i<=n;i++)
	{
		for(int j=0;j<l[i].size()-1;j++)
		{
			// cout<<l[i][j]<<" ";
			s[i].insert(l[i][j+1]-l[i][j]);
		}
	}
	build(1,0,n);
	while(q--)
	{
		int op,x;
		cin>>op>>x;
		if(op==1) 
		{
			if(a[x]==a[x+1]||x==n) continue;
			s[a[x]].erase(s[a[x]].find(l[a[x]][pos[x]]-l[a[x]][pos[x]-1]));
			s[a[x]].erase(s[a[x]].find(l[a[x]][pos[x]+1]-l[a[x]][pos[x]]));
			s[a[x+1]].erase(s[a[x+1]].find(l[a[x+1]][pos[x+1]]-l[a[x+1]][pos[x+1]-1]));
			s[a[x+1]].erase(s[a[x+1]].find(l[a[x+1]][pos[x+1]+1]-l[a[x+1]][pos[x+1]]));
			l[a[x]][pos[x]]++,l[a[x+1]][pos[x+1]]--,swap(pos[x],pos[x+1]),swap(a[x],a[x+1]);
			s[a[x]].insert(l[a[x]][pos[x]]-l[a[x]][pos[x]-1]);
			s[a[x]].insert(l[a[x]][pos[x]+1]-l[a[x]][pos[x]]);
			s[a[x+1]].insert(l[a[x+1]][pos[x+1]]-l[a[x+1]][pos[x+1]-1]);
			s[a[x+1]].insert(l[a[x+1]][pos[x+1]+1]-l[a[x+1]][pos[x+1]]);
			update(1,0,n,a[x]),update(1,0,n,a[x+1]);
		}
		else cout<<query(1,0,n,x)<<'\n';
	}

	return 0;
}
/*
7 6
0 1 0 2 1 0 3
2 2
2 3
2 4
1 4
2 3
2 4
*/

C. 勾指起誓

抽象题——45pts解法

以每一个人是否淘汰为状态,问题为边,在图上跑 \(dp\) ,共 \(2^m\) 个点,每个点 \(n\) 条出边,一个问题多次问是无意义的,所以可以看作每次等概率的选一个问题,求每个状态的概率。注意到有多个问题贡献同一条边,可以统一算。统计每条边上的问题数量 \(cnt_i\) , 再统计每个状态可以通过共多少个问题转移出去,记为 \(num_i\) ,考虑 \(dp\) 方程,设 \(f_i\) 表示有多少中问题排列方式可以转移到 \(i\) ,枚举转移的边 \(j\),\(f_{i \& j}+=f_{i}*cnt_{j}*A^{num_i-1-num_{i\&j}}_{num_i-1}\),指减去这个边的这个问题后,对 \(i\&j\) 无贡献的有 \(num_i-1-num_{i\&j}\) 条边,他们选出来后随机排列。

点击查看代码


#include<bits/stdc++.h>
const int mod=998244353;
const int maxn=2e5+10;
using namespace std;
int n,m,ans[25],cnt[(1<<21)+10],num[(1<<21)+10],f[(1<<21)+10],jc[maxn],ny[maxn];
string s;

int qpow(int x,int y)
{
	int ans=1;
	while(y)
	{
		if(y&1) ans=1ll*ans*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return ans;
}

void pre(int n)
{
	jc[0]=ny[0]=1;
	for(int i=1;i<=n;i++) jc[i]=1ll*jc[i-1]*i%mod;
	ny[n]=qpow(jc[n],mod-2);
	for(int i=n-1;i>=1;i--) ny[i]=1ll*ny[i+1]*(i+1)%mod;
}

int c(int n,int m)
{
	return 1ll*jc[n]*ny[m]%mod;
}

int main()
{
	freopen("yilihun.in","r",stdin);
	freopen("yilihun.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	pre(n);
	for(int i=1;i<=n;i++)
	{
		s.clear();
		cin>>s,s=" "+s;
		int k=0;
		for(int j=m;j>=1;j--)if(s[j]=='1') k|=(1<<(m-j));
		cnt[k]++;
	}
	for(int i=0;i<(1<<m);i++)
	{
		for(int j=0;j<(1<<m);j++)
		{
			if((i&j)&&(i&j)<i)
			{
				num[i]+=cnt[j];
			}
		}
	}
	f[(1<<m)-1]=c(n,num[(1<<m)-1]);
	// cout<<num[(1<<m)-1]<<endl;
	for(int i=(1<<m)-1;i>=0;i--)
	{
		if(f[i])
		{
			// cout<<i<<endl;
			if(!num[i])
			{
				for(int j=0;j<m;j++)
				{
					if((1<<j)&i) ans[j+1]+=f[i],ans[j+1]%=mod;
				}
			}
			else
			{
				for(int j=0;j<(1<<m);j++)
				{
					if(cnt[j]&&(i&j)&&(i&j)<i)
						f[i&j]=(f[i&j]+1ll*f[i]*cnt[j]%mod*c(num[i]-1,num[i&j])%mod)%mod;
				}
			}
		}
	}
	for(int i=1;i<=m;i++) cout<<ans[m-i+1]<<'\n';

	return 0;
}
/*

*/

D. 第八交响曲

双调排序板子

点击查看代码


#include<bits/stdc++.h>
const int maxn=210;
using namespace std;
int n,m,pos[maxn][maxn],pos2[maxn];
vector<pair<int,int> >ans[maxn];
void solve(int l,int r,int dep,int now)
{
	if(l==r) return ;
	if(!pos[now][dep]) pos[now][dep]=++m;
	int mid=l+r>>1;
	for(int i=l,j=mid+1;j<=r;i++,j++)
		ans[pos[now][dep]].push_back({i,j}); 
	solve(l,mid,dep+1,now),solve(mid+1,r,dep+1,now);
}

void lsx(int l,int r,int dep)
{
	if(l==r) return ;
	int mid=l+r>>1;
	lsx(l,mid,dep+1),lsx(mid+1,r,dep+1);
	if(!pos2[dep]) pos2[dep]=++m;
	for(int i=l,j=r;j>=mid+1;i++,j--)
		ans[pos2[dep]].push_back({i,j});
	solve(l,mid,dep+1,dep),solve(mid+1,r,dep+1,dep);
}

int main()
{
	freopen("symphony.in","r",stdin);
	freopen("symphony.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;int p=n;
	n=pow(2,ceil(log2(n)));
	lsx(1,n,1);
	cout<<m<<'\n';
	for(int i=1;i<=m;i++)
	{	
		for(auto j:ans[i])
			if(j.first<=p&&j.second<=p)
				cout<<"CMPSWP R"<<j.first<<" R"<<j.second<<" ";
		cout<<'\n';
	}
			

	return 0;
}
/*

*/

stars

image

posted @ 2024-11-14 21:40  _君の名は  阅读(21)  评论(0编辑  收藏  举报