首页 > 其他分享 >20230712 NOIP模拟(1)

20230712 NOIP模拟(1)

时间:2023-09-29 17:44:10浏览次数:38  
标签:石子 le 20230712 NOIP int ll 位置 SG 模拟

20230712 NOIP模拟(1)

[TOC]

总结

暑期第一次模拟赛

预估得分:40 分

实际得分:40 分

(有大佬AK力 Orz)

T1 前缀和 (pre)

题意

给定一个字符串,求所有长度为偶数的前缀在整个字符串中出现的次数和。

\(|S|\le200000\)。

分析

由于 KMP 的 \(p[i]\) 表示子串 \(\left[1\cdots p[i]\right]\) 和子串 \(\left[i-p[i]+1\cdots i\right]\) 相同,所以长度为 \(i\) 的前缀出现的次数就可以计入长度为 \(p[i]\) 的前缀出现次数中。

考虑 DP。

定义 \(f[i]\) 表示前缀 \(1\cdots i\) 中偶数串出现的次数,状态转移方程为:

\[ f[i]=f[p[i]]+(i\&1\oplus1) \]

其中 \(p[i]\) 为 KMP 中的 \(next[i]\) 数组。

代码

#include<bits/stdc++.h>
using namespace std;
#define N 200200

char c[N];
int l,ans;
int nxt[N],f[N];

int main(){
	freopen("pre.in","r",stdin);
	freopen("pre.out","w",stdout);
	cin.sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>c+1;
	l=strlen(c+1);
	int j=0;
	for(int i=2;i<=l;i++){
		while(j&&c[i]!=c[j+1]){
			j=nxt[j];
		}
		if(c[i]==c[j+1]) j++;
		nxt[i]=j;
	}                       
	for(int i=2;i<=l;i++){
		f[i]=f[nxt[i]]+(i&1^1);
		ans+=f[i];
	}
	cout<<ans<<"\n";
	
	return 0;
}

T2 构造完全图 (gouzao)

题意

对于完全图 \(G\),若有且仅有一棵最小生成树 \(T\),则称完全图 \(G\) 是由 \(T\) 拓展出的。给你一颗树 \(T\) ,找出 \(T\) 能拓展出的边权和最小的完全图 \(G\),求出 \(G\) 的边权和。

分析

考虑两个完全图 \(G_1\) 和 \(G_2\),已知 \(G_1\) 和 \(G_2\) 唯一的最小生成树 \(T_1\) 和 \(T_2\)。现在存在 \(u\in G_1\) 且 \(v\in G_2\),连边 \((u,v)\),长度为 \(w\)。现在要连 \(|G_1|\times |G_2|-1\) 条边,把这两个图合并成一个完全图,使得这个完全图唯一的最小生成树由 \(T_1\) 与 \(T_2\) 中的边与 \((u,v)\) 构成,易得这些边的边权都要大于 \(w\)。 整个过程从小到大加入边,合并并查集即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define N 100100
#define ll long long

inline void read(ll &a){
	a=0;
	ll f=1;
	char c=getchar();
	while((c<'0'||c>'9')&&c!='-'){
		c=getchar();
	}
	if(c=='-'){
		f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		a=(a<<1)+(a<<3)+(c^48);
		c=getchar();
	}
	a*=f;
}

ll n,ans;
ll fa[N],a[N];

struct edge{
	ll u,v,w;
	bool operator <(const edge &t)const{
		return w<t.w;
	}
}e[N<<1];

int find(int x){
	return x==fa[x]?x:fa[x]=find(fa[x]);
}

void merge(int x,int y,ll w){
	int fx=find(x),fy=find(y);
	if(fx==fy) return ;
	ans+=(a[fx]*a[fy]-1)*(w+1);
	fa[fx]=fy;
	a[fy]+=a[fx];
}

int main(){
	freopen("gouzao.in","r",stdin);
	freopen("gouzao.out","w",stdout);
	read(n);
	for(int i=1;i<=n;i++){
		fa[i]=i;
		a[i]=1;
	}
	for(int i=1;i<n;i++){
		read(e[i].u);read(e[i].v);read(e[i].w);
		ans+=e[i].w;
	}
	sort(e+1,e+n);
	for(int i=1;i<n;i++){
		merge(e[i].u,e[i].v,e[i].w);
	}
	printf("%lld\n",ans);
	
	return 0;
}

T3 独木桥 (bridge)

题意

在一个长度无限长的实数轴,有若干实数点。数轴从左到右坐标不断 增大。

每个点的位置用相对于数轴原点的点的坐标来表示。初始时 \(n\) 个点在 \(n\) 个互不相同的整点上。

每个点有一个初始朝向 \(d_i\)(\(d_i=0\) 则初始向左,\(d_i=1\) 则初始向右)。任何时刻所有的点都会以每秒 \(1\) 单位长度的速度匀速向所朝的方向移动。当某一时刻两个点同时移动到了同一个位置上,它们会立即改变自己的朝向(从左向 右变成从右向左,反之亦然),然后继续移动。

有 \(q\) 次询问,每次询问给定 \(k_i\) 与 \(t_i\),询问在 \(t_i\) 秒后,孩子 \(k_i\) 目前的位置。

\(1 \le n,q \le 2\times10^5,0 \le k_i<n,0\le p_i,t_i\le10^9,d_i\in\{0,1\}\)。

分析

我们可以发现两点性质:

  1. 点在不断移动的过程中,他们的相对位置顺序永远不变。

  2. 假设相遇的点不会掉转方向(即擦肩而过),位置集合与相遇时调转方向的情况相同 然后对于每个 \(i\),求出第 \(i\) 个孩子的位置排名(从小到大)\(rank_i\),一组询问转化成求 \(S\)(\(t_i\) 秒后位置集合)中第 \(rank_i\) 小的数 把向左和向右的点分开处理,二分答案即可。

复杂度为 \(O\left(nlog^2n\right)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define N 200200
#define ll long long

int n,q;
int rk[N];
struct node{
	ll p;
	int d,id;
	bool operator <(const node &t)const{
		return p<t.p;
	}
}x[N];

ll a[N],b[N];
int cnt1,cnt2;

inline int check(ll x,int t){
	int ret1,ret2;
	ret1=upper_bound(a+1,a+cnt1+1,x-t)-a-1;
	ret2=upper_bound(b+1,b+cnt2+1,x+t)-b-1;
	return ret1+ret2;
}

int main(){
	freopen("bridge.in","r",stdin);
	freopen("bridge.out","w",stdout);
	cin.sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>x[i].p;
		x[i].id=i;
	}
	for(int i=1;i<=n;++i){
		cin>>x[i].d;
	}
	sort(x+1,x+n+1);
	for(int i=1;i<=n;++i){
		rk[x[i].id]=i;
		if(x[i].d) a[++cnt1]=x[i].p;
		else b[++cnt2]=x[i].p;
	}
	cin>>q;
	for(int i=1;i<=q;++i){
		int k,t;
		cin>>k>>t;
		k=rk[k+1];
		ll l=x[1].p-t,r=x[n].p+t,ans;
		while(l<=r){
			ll mid=l+r>>1;
			if(check(mid,t)>=k){
				r=mid-1;
				ans=mid;
			} 
			else{
				l=mid+1;
			}
		}
		cout<<ans<<"\n";
	}
	
	return 0;
}

这题数据比较友好,打部分分也能打到不少。

对于20%的数据,\(n,p_i,t_i\le 10\)。

另有10%的数据,\(d_i\) 均相等。

另有20%的数据,\(q\le 10\)。

另有15%的数据,\(t_i\le100\)。

另有20%的数据,\(n\le 1000\)。

算法一

对于 \(d_i\) 相等的情况。

根据上述第一条性质,易知对于每一个点 \(i\),其在 \(t_i\) 秒后的位置为 \(p_i\pm t_i\)($d_i$为 \(1\) 时取 \(+\),\(d_i\) 为 \(0\) 时取 \(-\))。

复杂度为 \(O(1)\)。

期望得分 10 分。

算法二

考虑上述两条性质。

不考虑相遇后方向,计算每个点 \(i\) 在 \(t_i\) 秒的位置。

根据性质一,因为每个点的相对位置不变,所以点 \(i\) 的位置即为此时排名为 \(rk_i\) 的点所在的位置。

可将问题离线,按照 \(t_i\) 排序,对于每个询问,对遍历所有点,计算在不考虑反向的情况下的位置,排序,此时第 \(rk[k_i]\) 个点的位置即为答案。

复杂度为 \(O(q(n+nlogn))\)。

实测可另得 60 分

算法三

对于 \(t_i\le 100\) 的情况

由于$t$较小,可以考虑预先求出每个时刻时各个点的位置,对于每个询问直接 \(O(1)\) 查询即可

复杂度为 \(O(q)\)

应该可另得 15 分

T4 放石子 (stone)

题意

Alice 与 Bob 在玩游戏 定义游戏规则如下:给一张 \(n\) 个点,\(m\) 条边的有向无环图,每条边有颜色 \(c\),在图上放了 \(q\) 颗石子,每颗石子在一个点上。每次操作时选择一个有出边且点上有石子的点 \(x\),从点上取走一颗石子,然后选 择一个颜色集合 \(S\),对于每条满足颜色 \(e\in S\) 的出边 \(i\),在边 \(i\) 的终点上放上一颗石子。双方轮流操作, 不能操作者负。问 Alice 是先手获胜还是后手获胜。

分析


公平博恋问题,我们要用到SG函数……

这是我能做的?再见!


贴一个老师给的题解

显然这是公平博恋,我们要用到 \(SG\) 函数。

我们将每个节点看成一个状态,将出度为 \(0\) 的点看成必败态。

首先我们知道每个石子是独立的,我们只需要考虑求一个节点 \(u\) 上有一个石子时的 \(SG(u)\) 然后将所有石子的对应的 \(SG\) 函数求异或和即可得到答案。

我们先拓扑排序,然后倒拓扑序递推。 我们把结点 \(u\) 的所有出边按颜色分类,如果 \(c\in S\),那么每种颜色为 \(c\) 的边我们必须同时选择,所以我们可以将这一类的权值记为:

\[ \begin{align} &\oplus(u,v)\in E\\ &(u,v)\text{的颜色}=cSG(v) \end{align} \]

我们将这个权值构成的集合称作 \(A\)。

那么我们所有决策对应的 \(SG\) 函数构成的集合就是 \(\{\oplus_{x\in B}|B\subset A\}\)。我们要求的就是从这个集合中任意选取一个子集,然后异或起来最小的得不到的数,\(mex\{\oplus_{x\in B}x\subset A\}\)。只有将 \(A\) 内的元素插入线性基,然后找不在线性基中的最低位,即最小的线性相关的位,设为第 \(i\) 位,就有 \(SG(u)=mex\{\oplus_{x\in B}x|B\subset A\}=2^i\) 并且求 \(SG\) 函数值的位数最坏情况下是 \(O(n)\) 的,我们需要用 bitset 来储存答案。

总时间复杂度为 \(O\left(\frac{|A|\times n^2}{64}\right)\)。

标签:石子,le,20230712,NOIP,int,ll,位置,SG,模拟
From: https://www.cnblogs.com/WANG-YIN/p/17737137.html

相关文章

  • 使用链表模拟队列和栈
    使用链表模拟队列案例1//创建节点类publicclassNode{intn;Nodenext;}//编写方法publicclassQueue{Nodehead=newNode();Nodelast=newNode();privateintlen=0;publicintsize(){returnthis.len;}......
  • 使用数组模拟队列和栈
    使用数组模拟队列案例1publicclassQueue{privateint[]num=newint[5];privateintlen=0;publicintsize(){returnthis.len;}//添加publicintadd(intn){if(len<num.length){num[len]=n;......
  • 模拟链表
    创建节点类publicclassNode{intn;Nodenext;}编写方法publicclassMyLinkList{Nodehead=newNode();privateintlen=0;//获取长度publicintsize(){returnlen;}//添加元素到最后publicvoid......
  • 使用数组模拟集合
    编写方法publicclassMyArrayList{privateint[]n=newint[10];//动态数组privateintsize=0;//长度publicintsize(){returnthis.size;}//添加一个元素publicvoidadd(intelement){n[size]=element;......
  • P1075 [NOIP2012 普及组] 质因数分解
    因为n是两个质数的乘积,所以直接暴力枚举,只要能被整除,直接输出因为是要求大的那个,所以从小到大枚举,输出商即可点击查看代码#include<bits/stdc++.h>usingnamespacestd;#defineLLlonglongintmain(){ LLn; cin>>n; for(inti=2;1LL*i*i<=n;i++){ if......
  • 国庆NOIP储备营讲课笔记
    Day1(基础算法)讲师:余快枚举法例题1给定一个数\(x\),判断\(x\)是不是质数。朴素算法:枚举\([2,x−1]\)之间所有的整数\(i\),逐个判断\(x\)是否被\(i\)整除,若都不能整除则\(x\)是质数,时间复杂度\(O(x)\),搞个\(10^9\)直接卡过。该怎么优化呢?优化枚举范围:只需枚举到......
  • 解题报告 P2680 [NOIP2015 提高组] 运输计划
    P2680[NOIP2015提高组]运输计划题目链接LCA的题,需要求最大值最小,考虑二分答案。先存储每组询问的距离。然后二分答案时找出所有比当前答案长的距离的重叠部分。在这些重叠部分中找出权值最大的边。判断最长链减去这条边是否小于等于当前答案。否则返回0代码如下/**@......
  • 济南 CSP-S NOIP 储备营笔记
    Day1上午——基础算法模拟+枚举小前言碰到题目不会做->先写个模拟压压惊()枚举法枚举的思想是不断地猜测,从所有可能的集合中一一尝试,然后再判断是否符合题目的条件。单独提到枚举时我们往往认为这是一个暴力做法,但事实上并非如此,恰当的枚举往往会是解题的关键步骤。......
  • 恩尼格玛机模拟动图
    打开恩尼格玛机模拟动图网站,可直接查看对应动图效果,具体操作如下:再次点击Encrypt后Output栏会和上次的不同..其他实际项参考下图,具体各项释义可查Enigma运行原理......
  • 模拟集成电路设计系列博客——2.2.1 折叠Cascode放大器的基本结构
    2.2.1折叠Cascode放大器的基本结构许多现代CMOS集成电路放大器设计仅用于驱动容性负载。由于驱动的是容性负载,放大器并不需要通过一个电压缓冲器来获得较低的输出阻抗。因此相比那些必须要驱动阻性负载的放大器,更可能获得更快的速度和更大的信号摆幅。而这些增长仅仅需要通过在......