首页 > 其他分享 >241115 noip 模拟赛

241115 noip 模拟赛

时间:2024-11-15 15:40:30浏览次数:1  
标签:frac noip int 复杂度 leq 241115 dp Theta 模拟

省流:\(90 + 100 + 25 + 10\)。

T1

题意:给定一个长为 \(n\) 的排列,定义一次操作为选出排列中至多 \(4\) 个不同的数,将它们任意重排,求最少操作次数让这个排列单调递增。

\(n \leq 10^6\)。

找出排列的所有置换环,设环长为 \(t_1,t_2,t_3,\cdots,t_m\),则答案为:

\[\sum_{i = 1}^m \lfloor \frac{t_i}{3} \rfloor + \lceil \frac{\sum_{i = 1}^m [t_i \% 3 = 2]}{2} \rceil \]

解释如下:

  • 若环长 \(> 4\),则一次至多只能到位 \(3\) 个数,若最后剩下 \(3\) 或 \(4\) 个,只能多操作一次。而剩余 2 个的情况可以两对两对处理。
  • 最优的操作方案即为:环长 \(> 4\) 时,每次到位 \(3\) 个;环长为 \(3\) 或 \(4\) 时,一次到位;两个环长为 \(2\) 的一次同时到位。

时间复杂度 \(\Theta(n)\)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int t,n,p[N],vis[N],sum[N];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>t;
	while(t--) {
		cin>>n;
		for(int i=1; i<=n; i++) cin>>p[i];
		int tot=0,ans=0;
		for(int i=1; i<=n; i++) vis[i]=false;
		int cnt1=0;
		for(int i=1; i<=n; i++) {
			if(vis[i]) continue;
			int cur=i,cnt=0;
			do {
				vis[cur]=true;
				cur=p[cur];
				cnt++;
			}while(cur!=i);
			if(cnt<=1) continue;
			ans+=cnt/3;cnt%=3;
			if(cnt==2) cnt1++;
		}
		cout<<ans+cnt1/2+cnt1%2<<endl;
	}
	return 0;
}

闲话:赛时写了个假完了的贪心,但是发现 \(n \leq 8\) 时卡不掉,特殊性质也卡不掉,有 \(90\) 分,所以不想改了\kx

T2

题意:有一张 \(n\) 个点,\(m\) 条边的图,你可以给每个点赋予互不相同的权值。你可以选择在任意节点出发,每次你可以走向这个与这个点相连的点中点权最小的点。请你找到一种赋予权值、以及选择开始节点的方案,使得你能够访问到的节点数最大(包括开始节点和结束节点),输出这个最大值。

\(n \leq 40\)。

直接暴搜,暴搜策略如下。

  • 标记当前点 \(u\),每次选择与 \(u\) 连边的未标记的点 \(v\),然后标记 \(u\) 的所有邻居,并走向 \(v\)。

容易证明这样的路径一定合法,我们只需要对每条路径的长度取最大值即可。

暴搜时间复杂度为什么是对的呢?

设 \(n\) 个点的时间复杂度为 \(T(n)\)。

若当前点 \(u\) 还有 \(k\) 个邻居没有被标记,那么走完这一步后,将会新标记 \(k\) 个点。

故 \(T(n) = T(n - k) \times k + \Theta(n)\),可以得出当 \(k = 3\) 时 \(T(n)\) 取得最劣,为 \(\Theta(3^{\frac{n}{3}} n)\)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=45;
vector<int> ve[N];
int n,m,vis[N],ans=0;
void dfs(int u,int dep) {
	ans=max(ans,dep);
	vector<int> tmp;
	for(int j=0; j<ve[u].size(); j++) if(!vis[ve[u][j]]) tmp.push_back(ve[u][j]),vis[ve[u][j]]=true;
	for(int i=0; i<tmp.size(); i++) dfs(tmp[i],dep+1);
	for(int j=0; j<tmp.size(); j++) vis[tmp[j]]=false;
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>m;
	for(int i=1; i<=m; i++) {
		int u,v;
		cin>>u>>v;
		ve[u].push_back(v);
		ve[v].push_back(u);
	}
	for(int i=1; i<=n; i++) dfs(i,1);
	cout<<ans;
	return 0;
}

闲话:其实赛时并不会证明这个复杂度,只是发现大样例跑的特别快,就没管了(

T3

题意:给定一个长为 \(n\) 的递增序列 \(a\),其中有一个数 \(a_k\) 是答案,每次你可以询问一个数 \(x\),然后得知 \(a_k\) 是 \(\geq x\) 还是 \(< x\),花费 \(\lvert a_k - x \rvert\) 的代价,你需要求出一个最优策略使得最坏情况下花费代价最小,输出最小值。

\(n \leq 1000,a_i \leq 10^9\)。

考虑区间 dp 表示已经确定答案在这个区间内还需要花费多少的代价,记录区间 \([l,r]\) 以及 \(x\) 表示左端点以前的询问个数和 \(y\) 表示右端点以后的询问个数,方便计算贡献。时间复杂度 \(\Theta(n^5)\)。发现我们只需要记录 \(x - y\) 的值,于是时间复杂度降为 \(\Theta(n^4)\)。发现这个区间 dp 满足四边形不等式,于是可以决策单调性优化,时间复杂度降为 \(\Theta(n^3)\)。稍加一点观察,发现 \(x - y\) 的值是 \(\log a_i\) 这个量级的,于是可以把这一维压成 \(\log a_i\),时间复杂度降为 \(\Theta(n^2 \log a_i)\),于是就可以通过了。

设 \(c\) 为最优操作中的 \(x − y\) 的值,\(\lvert c \rvert\) 是 \(\Theta(\log a_i)\) 级别的大致证明:

  • 设 \(v = a_n\),则答案 \(\leq v\)。策略是直接二分值域查询,代价为 \((\frac{1}{2} + \frac{1}{4} + \cdots) v \leq v\)。
  • 若 \(c = 0\) 时询问的 \(y < \frac{v}{3}\)。则 \(x\) 在右侧的代价至少为 \(\frac{2v}{3}\);\(x\) 在左侧的代价至少为 \(\frac{v}{3}\),此后也最多 \(\frac{v}{3}\)。所以左侧代价一定不超过右侧,故此时的最优询问点 \(x\) 一定在 \([\frac{v}{3},\frac{2v}{3}]\) 中。
  • 当 \(c != 0\) 时,只会赋一个 \(c\) 更趋于 \(0\) 的趋势,因此 \(\lvert c \rvert\) 是 \(\Theta(\log a_i)\) 级别的。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1005;
int n,a[N],dp[N][N][75],f[N][N][75];
signed main() {
	cin>>n;
	for(int i=1; i<=n; i++) cin>>a[i];
	int k=35;
	memset(dp,0x3f,sizeof(dp));
	for(int i=1; i<=n; i++) for(int j=0; j<=2*k; j++) dp[i][i][j]=(j-k)*a[i],f[i][i][j]=i;
	for(int len=2; len<=n; len++) {
		for(int l=1; l+len-1<=n; l++) {
			int r=l+len-1;
			for(int i=1; i<=2*k-1; i++) {
				int mn=LONG_LONG_MAX,pos;
				for(int j=f[l][r-1][i]; j<=min(f[l+1][r][i],r-1); j++) {
					int x=(dp[j+1][r][i+1]-dp[l][j][i-1])/2;
					x=max(x,a[j]+1),x=min(x,a[j+1]);
					int val=max(dp[l][j][i-1]+x,dp[j+1][r][i+1]-x);
					if(val<mn) mn=val,pos=j;
				}
				dp[l][r][i]=mn,f[l][r][i]=pos;
			}
		}
	}
	cout<<dp[1][n][k];
	return 0;
}

闲话:赛时会了 \(\Theta(n^4)\),但是边界问题一直没调出来,浪费很多时间,感觉调出来了的话赛时能写出正解。

T4

还不会。

标签:frac,noip,int,复杂度,leq,241115,dp,Theta,模拟
From: https://www.cnblogs.com/System-Error/p/18548101

相关文章

  • NOIP模拟赛 #11
    A一个\(R\timesC\)的矩阵\(A\),有\(N\)个位置已知,第\(i\)个为\(A_{r_i,c_i}=a_i\)。求是否存在一种填写剩下数字的方案,满足每个数字都非负且对于任意\(i,j(1\lei\leR-1,1\lej\leC-1)\)都有\(A_{i,j}+A_{i+1,j+1}=A_{i,j+1}+A_{i+1,j}......
  • [2024.11.15]NOIP 模拟赛
    赛后的思路永远比赛时清晰。赛时T1玩了一会发现\(a_3\sima_7\)一定是相邻的,所以只需要考虑两个数字即可。答案显然有单调性,所以考虑先二分\(a_2\),再二分\(a_1\)。两个二分的思路都很简单,第二个二分用lower_bound即可。第一个的话其实就是模拟lower_bound内置,赛时调......
  • CW 11.15 模拟赛记录
    看到说不按题目难度排序,先读下题初看\(\rm{T1}\)没什么思路\(\rm{T2}\)感觉像是\(\rm{dp}\),可能能多骗点?\(\rm{T3}\)又是计数\(\rm{T4}\)没思路感觉要寄,\(\rm{lhs}\)多半又要\(\rm{AK}\)\(\rm{T2}\)观察到这个类型的题比较熟,先开\(\rm{T2}\)简化题意......
  • 地面沉降数值模拟/三维地质建模数据处理技术应用
    地面沉降数值模拟实践技术应用与案例分析  目前,地面沉降问题是我国较为常见的环境地质问题,其巨大的破坏力严重影响城市建筑安全和交通轨道运行。围绕地面沉降的防控与治理,是工程地质、环境地质、轨道交通设计等相关技术人员十分关注的领域,而数值模拟技术是评估防控效果的有......
  • 【NOIP提高组】 传纸条
    【NOIP提高组】传纸条C语言版本C++版本Java版本......
  • 【洛谷】P1047 [NOIP2005 普及组] 校门外的树
    题目描述某校大门外长度为 l 的马路上有一排树,每两棵相邻的树之间的间隔都是 1 米。我们可以把马路看成一个数轴,马路的一端在数轴 00 的位置,另一端在 l 的位置;数轴上的每个整数点即 0,1,2,…,l都种有一棵树。由于马路上有一些区域要用来建地铁。这些区域用它们在数......
  • 冯梓轩2024.11.14模拟赛反思
    冯梓轩2024.11.14模拟赛反思今天算是把之前犯过的大多数错误都犯了一遍。其实主要问题还是出在T1上,当时一直在想能不能先将\(n\)转成三进制数,然后通过后续调整来将其变合法。但是这个思路想了接近3个半小时也不会做。中途我也没有尝试换一种思路,一直按照进制的方式去死磕,最......
  • NOIP 复习题之二分图
    CF741C有\(2n\)个人围成一圈坐在桌子边上,每个人占据一个位子,对应这\(2n\)个人是\(n\)对情侣,要求情侣不能吃同一种食物,并且桌子上相邻的三个人的食物必须有两个人是不同的,只有两种食物,问一种可行分配方式。思路:我们在两个点之间连边,表示他们吃的不一样。然后对于点对\((......
  • 2025 --炼石计划-- 11 月 13 日 --NOIP 模拟赛 #20
    2025--炼石计划--11月13日--NOIP模拟赛#20T1邻间的骰子之舞签到题显然答案具有二分性,考虑二分答案。注意到每次有意义的复制会使长度翻倍,即最多复制\(60\)次,而粘贴则类似一个乘积的形式,check时可以枚举复制次数,此时则能知道粘贴次数,由和定平分时积最大得到最大长度......
  • NOIP 模拟赛 #20
    已经好久没写模拟赛题解了啊。。。A.邻间的骰子之舞一个结论,可以打表,每一次复制后跟的粘贴数量要尽量相同,差不超过1,所以枚举复制了几次,然后二分最大的出来答案小于\(n\)的数\(mid\),然后枚举多少个复制后的粘贴数为\(mid+1\),出来的答案可以\(O(1)\)算,大于\(n\)直接输出......