首页 > 其他分享 >【考试题解】NOIP2024(欢乐)加赛3

【考试题解】NOIP2024(欢乐)加赛3

时间:2024-11-14 17:31:01浏览次数:1  
标签:1000001 int long times 加赛 考试题 ri NOIP2024 define

目录

A. Sakurako and Water

题目内容

给你一个 \(n \times n\) 的带权矩阵,每次操作选中一个正方形区域并把从左上角到右下角的对角线(主对角线)上的每个格子的权值 \(+1\),求使整个矩阵所有点权值非负的最小操作次数

思路

有一个显然的性质:对于矩阵中任意一条主对角线进行操作,如果它还能再向左上或右下扩展,那么一定不如扩展到不能再扩展更优。这样,整个矩形只剩下了 \(2n-1\) 条有用的主对角线。对一条主对角线的最小操作次数就是在它上面的点的最小权值的绝对值。直接左右反转整个矩阵,然后对于每个点,找到它属于哪个从左下到右上的对角线是好做的。最后枚举对角线统计答案。

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b,c[505][505],mx[1001];
long long ans;
int main()
{
	scanf("%d",&a);
	while(a--)
	{
		scanf("%d",&b);
		for(ri i=1;i<=b;i++)
		{
			for(ri j=b;j>=1;j--)
			{
				scanf("%d",&c[i][j]);
			}
		}
		memset(mx,0,sizeof(mx));
		for(ri i=1;i<=b;i++)
		{
			for(ri j=1;j<=b;j++)
			{
				mx[i+j-1]=min(mx[i+j-1],c[i][j]);
			}
		}
		ans=0;
		for(ri i=1;i<=b<<1;i++)
		{
			ans-=mx[i];
		}
		printf("%lld\n",ans);
	}
	return 0;
}

B. Binomial Coefficients, Kind Of

题目内容

给你一个错误的递推求组合数的代码:

for(int n = 0; n < N; n++) {
    C[n][0] = 1;
    C[n][n] = 1;
    for(int k = 1; k < n; k++)
        C[n][k] = C[n][k-1] + C[n-1][k-1];
}

\(t\) 次询问,每次给定 \(n,k\),求出这个程序会输出的 \(C[n][k]\)。\(1 \le t \le 10^5\),\(1 \le k \lt n \le 10^5\)。

思路

打表找规律可以发现当 \(k=0\) 或 \(k=n\) 时输出为 \(1\),否则为 \(2^k\)。建出错误的杨辉三角,第 \(0\) 列必定为 \(1\),第 \(1\) 列应该为第 \(0\) 列相邻两数相加,为 \(2\);第 \(2\) 列应该为第 \(1\) 列相邻两数相加,为 \(2 \times 2\);第 \(3\) 列应该为第 \(2\) 列相邻两数相加,为 \(2^3\)。然后正确性此时已经很显然了。但是还有特殊情况,就是 \(k=n\) 的,判掉就好了。快速幂直接做。

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b[100001],c[100001];
const int mod=1e9+7;
long long jc[100001],ny[100001];
il long long qpow(long long x,long long y)
{
	register long long rn=1;
	while(y)
	{
		if(y&1)
		{
			rn=(rn*x)%mod;
		}
		x=(x*x)%mod;
		y>>=1;
	}
	return rn;
}
il long long Cc(int x,int y)
{
	if(!y||x==y)
	{
		return 1;
	}
	else
	{
		return qpow(2,y);
	}
}
int main()
{
	scanf("%d",&a);
	for(ri i=1;i<=a;i++)
	{
		scanf("%d",&b[i]);
	}
	for(ri i=1;i<=a;i++)
	{
		scanf("%d",&c[i]);
	}
	for(ri i=1;i<=a;i++)
	{
		printf("%lld\n",Cc(b[i],c[i]));
	}
	return 0;
}

C. QED's Favorite Permutation

题目内容

给定一个 \(n\) 的排列 \(p\) 和一个长为 \(n\) 的字符序列 \(s\)。如果 \(s_i='L'\),那么我们可以在任意时刻交换 \(p_{i-1}\) 和 \(p_i\);如果 \(s_i='R'\),那么我们可以在任意时刻交换 \(p_{i+1}\) 和 \(p_i\)。保证 \(s\) 只包含以上两种字符。现在对序列 \(s\) 进行 \(q\) 次修改,每次给定一个位置 \(x\),如果 \(s_x='L'\),将其变为 \(R\);否则将其变为 \(L\)。询问每次修改后是否可以通过若干次操作使排列 \(p\) 单调递增。

思路

排列变有序,那么每个数该去的位置是好找的。如果所有该往左走的数都满足条件,那么整个序列也就可以变为有序的了。于是首先维护需要在哪些位置向左走,假设 \(i\) 需要向左移动到 \(j\),那么从 \(j+1\) 到 \(i\) 的所有点都需要可以向左。由于我们从前到后遍历排列 \(p\),所以我们每个需要向左的区间的右端点是单调的,直接 vector 维护;然后对每个需要向右的位置赋值为 \(1\),再把每个字符贡献的位置 \(+1\),能达到目标就是序列里没有负数。可以线段树做,也可以直接在序列上操作。前者复杂度 \(O(n\log n)\),后者复杂度 \(O(n)\)。下面只给出 \(O(n)\) 解法代码。

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b,c,d[200002],u,can[200002],num;
vector<pair<int,int>>vec;
char e[200002];
int main()
{
	scanf("%d",&a);
	while(a--)
	{
		scanf("%d%d",&b,&c);
		vec.clear();
		for(ri i=1;i<=b;i++)
		{
			scanf("%d",&d[i]);
			if(d[i]<i)
			{
				while(!vec.empty())
				{
					if(vec.back().first>=d[i]+1)
					{
						vec.pop_back();
					}
					else
					{
						break;
					}
				}
				if(!vec.empty()&&vec.back().second>=d[i]+1)
				{
					vec.back().second=i;
				}
				else
				{
					vec.push_back({d[i]+1,i});
				}
			}
		}
		scanf("%s",e+1);
		memset(can,0,sizeof(can));
		num=0;
		for(register auto i:vec)
		{
			for(ri j=i.first;j<=i.second;j++)
			{
				can[j]=-1;
				num++;
			}
		}
		for(ri i=1;i<=b;i++)
		{
			if(e[i]=='L')
			{
				if(can[i]<0)
				{
					num--;
				}
				can[i]++;
			}
			else
			{
				if(can[i+1]<0)
				{
					num--;
				}
				can[i+1]++;
			}
		}
		while(c--)
		{
			scanf("%d",&u);
			if(e[u]=='L')
			{
				e[u]='R';
				can[u]--;
				if(can[u]<0)
				{
					num++;
				}
				if(can[u+1]<0)
				{
					num--;
				}
				can[u+1]++;
			}
			else
			{
				e[u]='L';
				can[u+1]--;
				if(can[u+1]<0)
				{
					num++;
				}
				if(can[u]<0)
				{
					num--;
				}
				can[u]++;
			}
			if(!num)
			{
				puts("YES");
			}
			else
			{
				puts("NO");
			}
		}
	}
	return 0;
}

D. Card Game

题目内容

一种双人卡牌游戏中有 \(n \times m\) 张卡牌,每张卡牌 \(i\) 由两个数描述:花色 \(x_i\) 和 等级 \(y_i\)。花色编号从 \(1\) 到 \(n\),等级编号从 \(1\) 到 \(m\) 。规定卡牌 \(i\) 能击败卡牌 \(j\) 当且仅当满足下面两个条件之一:

  • \(x_i=1,x_j \neq 1\)

  • \(x_i=x_j,y_i \gt y_j\)

游戏开始时将牌均分。规定 \(1\) 号玩家能够获胜,当且仅当存在一种将两人获得的牌一一对应的方案,使得 \(1\) 号玩家的每张牌都可以击败对应的 \(2\) 号玩家的牌。给定 \(n,m\),求有多少种方案使得 \(1\) 号玩家获胜。答案对 \(998244353\) 取模。保证 \(m\) 是偶数。

思路

首先忽略掉花色 \(1\) 产生的影响,只考虑在同一个花色内的合法方案。这个直接 dp 即可,设 \(f_{i,j}\) 表示考虑了前 \(i\) 个数有 \(j\) 个数还没有匹配(在 \(2\) 手上)的方案数,转移考虑该位被 \(1\) 还是 \(2\) 拿走,也就是 \(f_{i,j}=f_{i-1,j-1}+f_{i-1,j+1}\)。容易证明 \(j \ge 0\) 的方案一定没有任何作用。然后加上 \(1\) 的影响,再来个 dp。由于除了 \(1\) 花色之外别的花色是相互独立的,找找规律发现别的花色从 \(1\) 这里“搬救兵”,每次一定搬 \(2\) 个。这时,我们前一个 dp 的状态设计就巧妙地和这里的解法结合了起来:设 \(g_{i,j}\) 表示考虑了前 \(i\) 个花色(不包含 \(1\)),有 \(j\) 对数等待匹配的方案数,转移枚举当前花色贡献的等待匹配的对数。最后求答案把每个对数对应的方案数乘上对应的 \(1\) 花色方案即可。这里可以再求一遍,但是有一个好用的结论:有 \(i\) 对数等待匹配的方案树和还可以再匹配 \(i\) 对数的方案数相同,证明考虑把玩家 \(1\) 的选牌集合和玩家 \(2\) 的选牌集合互换。然后直接求 \(\sum \limits_{i=0}^{\tfrac{m}{2}}f_{m,i} \times g_{n-1,i}\)。无需任何优化,复杂度 \(O(n^3)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b;
const int mod=998244353;
long long dp[505][505],ans,jc[1001],ny[1001],num[505],gt[505][505];
il long long qpow(long long x,long long y)
{
	register long long rn=1;
	while(y)
	{
		if(y&1)
		{
			rn=(rn*x)%mod;
		}
		x=(x*x)%mod;
		y>>=1;
	}
	return rn;
}
il long long C(int x,int y)
{
	return (((jc[x]*ny[x-y])%mod)*ny[y])%mod;
}
int main()
{
	scanf("%d%d",&a,&b);
	jc[0]=ny[0]=1;
	for(ri i=1;i<=a+b;i++)
	{
		jc[i]=(jc[i-1]*i)%mod;
		ny[i]=qpow(jc[i],mod-2);
	}
	dp[0][0]=1;
	for(ri i=1;i<=b;i++)
	{
		for(ri j=0;j<=i;j++)
		{
			if(j)
			{
				dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
			}
			if(j<i)
			{
				dp[i][j]=(dp[i][j]+dp[i-1][j+1])%mod;
			}
		}
	}
	if(a==1)
	{
		printf("%lld\n",dp[b][0]);
		return 0;
	}
	for(ri i=0;i<=(b>>1);i++)
	{
		gt[1][i]=dp[b][i<<1];
	}
	for(ri i=2;i<a;i++)
	{
		for(ri j=0;j<=(b>>1);j++)
		{
			for(ri k=0;k<=j;k++)
			{
				gt[i][j]+=(gt[i-1][k]*dp[b][(j-k)<<1])%mod;
				gt[i][j]%=mod;
			}
		}
	}
	for(ri i=0;i<=(b>>1);i++)
	{
		ans+=(dp[b][i<<1]*gt[a-1][i])%mod;
		ans%=mod;
	}
	printf("%lld",ans);
	return 0;
}

E. Long Way to be Non-decreasing

题目内容

给你一个长为 \(n\) 的数列 \(a\) 和一个长为 \(m\) 的数列 \(b\),保证 \(1 \le a_i,b_i \le m\)。定义一次操作如下:

  • 选定一个下标集合 \(S\)。

  • 对于 \(\forall i \in S,a_i \gets b_{a_i}\)

输出使 \(a\) 单调不降的最小操作次数,无解输出 \(-1\)。

思路

首先注意到由于集合任选,所以答案是具有显然的单调性的,于是二分答案。如果暴力 \(O(n^2)\) check 可以喜提 \(16pts\) 高分。暴力的思路大概就是对于当前的 mid 贪心找能到达的、不小于上一个数的2最小值,找不到就返回 false。\(b\) 序列内元素相互映射,如果连边,应该是恰好 \(m\) 条边,于是想到基环树。事实上连出来的是一个内向基环树森林。然后 check 中的可达转化为基环树上距离 \(\le mid\)。问题来到如何处理基环树上距离。分情况讨论:

  • 不在一个连通块里,必不可达。

  • 在同一棵树上,终点不在环上。以环为根,但是二者不在同一颗子树内,或者在同一颗子树内但是不是祖先关系,则必不可达;否则就是二者的深度差。

  • 终点在环上。距离分为从子树走到环上的距离和环上距离。前一个和前面的处理方法相同,后一个可以给环钦定一个起点,然后处理出每个点离起点的距离。

但是到了这一步好像 check 还是 \(O(n^2)\) 的。但是注意到我们在 check 里构造的那个序列里的元素一定单调不降,于是枚举是从前一个元素开始枚举即可,均摊就是 \(O(n)\) 的了。总复杂度 \(O(Tn \log n)\),\(T\) 是多测数据组数。

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b,c,d[1000001],e[1000001],f[1000001],g,cnt,dfs[1000001],low[1000001],len[1000001],dep[1000001],in[1000001],out[1000001],sum[100001],be[1000001],hn[1000001],ua;
stack<int>use;
vector<int>vec[1000001];
bool col[1000001],ck[1000001];
struct BCJ
{
	int fa[1000001],siz[1000001];
	il void build(int x)
	{
		for(ri i=1;i<=x;i++)
		{
			fa[i]=i;
			siz[i]=1;
		}
	}
	il int find(int x)
	{
		if(fa[x]!=x)
		{
			fa[x]=find(fa[x]);
		}
		return fa[x];
	}
	il bool merge(int x,int y)
	{
		x=find(x),y=find(y);
		if(x==y)
		{
			return false;
		}
		if(siz[x]<siz[y])
		{
			swap(x,y);
		}
		fa[y]=x;
		siz[x]+=siz[y];
		return true;
	}
}tree;
struct node
{
	int h,to;
}pic[1000001];
il void ndin(int x,int y)
{
	g++;
	pic[g].to=y;
	pic[g].h=f[x];
	f[x]=g;
}
void tarjan(int x)
{
	cnt++;
	dfs[x]=low[x]=cnt;
	ck[x]=true;
	use.push(x);
	for(ri i=f[x];i;i=pic[i].h)
	{
		ri y=pic[i].to;
		if(y==x)
		{
			ua++;
			hn[x]=ua;
			col[x]=true;
			use.pop();
			sum[ua]++;
			ck[x]=false;
			return;
		}
		if(!dfs[y])
		{
			dep[y]=dep[x]+1;
			tarjan(y);
			low[x]=min(low[x],low[y]);
		}
		else if(ck[x])
		{
			low[x]=min(low[x],dfs[y]);
		}
	}
	if(dfs[x]==low[x])
	{
		if(use.top()!=x)
		{
			ua++;
			while(use.top()!=x)
			{
				ri i=use.top();
				hn[i]=ua;
				col[i]=true;
				len[i]=dep[i]-dep[x];
				ck[i]=false;
				use.pop();
				sum[ua]++;
			}
			ck[x]=false;
			col[x]=true;
			hn[x]=ua;
			len[x]=0;
			use.pop();
			sum[ua]++;
		}
		else
		{
			ck[x]=false;
			use.pop();
		}
	}
}
void dfs0(int x,int y)
{
	be[x]=y;
	cnt++;
	in[x]=cnt;
	for(ri i:vec[x])
	{
		if(!col[i])
		{
			dep[i]=dep[x]+1;
			dfs0(i,y);
		}
	}
	out[x]=cnt;
}
il int dist(int x,int y)
{
	if(x==y)
	{
		return 0;
	}
	if(tree.find(x)!=tree.find(y))
	{
		return inf;
	}
	if(col[y])
	{
		if(len[y]>len[be[x]])
		{
			return dep[x]+len[y]-len[be[x]];
		}
		else
		{
			return dep[x]+(sum[hn[y]]-(len[be[x]]-len[y]))%sum[hn[y]];
		}
	}
	if(be[x]!=be[y]||in[y]>=in[x]||out[y]<in[x])
	{
		return inf;
	}
	return dep[x]-dep[y];
}
il bool check(int x)
{
	ri re=1;
	for(ri i=1;i<=b;i++)
	{
		while(re<=c&&dist(d[i],re)>x)
		{
			re++;
		}
		if(re>c)
		{
			return false;
		}
	}
	return true;
}
int main()
{
	scanf("%d",&a);
	while(a--)
	{
		scanf("%d%d",&b,&c);
		register bool te=true;
		for(ri i=1;i<=b;i++)
		{
			scanf("%d",&d[i]);
			if(d[i]<d[i-1])
			{
				te=false;
			}
		}
		fill(f+1,f+1+c,0);
		g=0;
		tree.build(c);
		for(ri i=1;i<=c;i++)
		{
			vec[i].clear();
		}
		for(ri i=1;i<=c;i++)
		{
			scanf("%d",&e[i]);
			ndin(i,e[i]);
			vec[e[i]].push_back(i);
			tree.merge(i,e[i]);
		}
		if(te)
		{
			puts("0");
			continue;
		}
		cnt=0;
		fill(dfs+1,dfs+1+c,0);
		fill(sum+1,sum+1+c,0);
		fill(col+1,col+1+c,false);
		ua=0;
		for(ri i=1;i<=b;i++)
		{
			if(!dfs[i])
			{
				dep[i]=0;
				tarjan(i);
			}
		}
		for(ri i=1;i<=c;i++)
		{
			if(col[i])
			{
				dep[i]=0;
				cnt=0;
				dfs0(i,i);
			}
		}
		ri m=1,n=c;
		while(m!=n)
		{
			ri l=(m+n)>>1;
			if(check(l))
			{
				n=l;
			}
			else
			{
				m=l+1;
			}
		}
		if(!check(m))
		{
			puts("-1");
		}
		else
		{
			printf("%d\n",m);
		}
	}
	return 0;
}

F. Many Games

题目内容

给你 \(n\) 个物品,每个物品有一个概率 \(p_i\)% 和权值 \(w_i\),设 \(S\) 表示物品集合,定义如下函数:

\[f(s)= \forall i \in S,\left ( \prod \limits_{i} \tfrac{p_i}{100} \right ) \times \left ( \sum \limits_{i} w_i \right ) \]

求 \(f(S)\) 的最大值。

思路

以下推式子部分默认 \(p\) 表示概率,也就是乘过 \(\tfrac{1}{100}\)。

这个东西不好直接 dp 答案,所以把函数中的一个东西放到 dp 状态里。显然你很难把概率放到状态上,所以设 \(dp_{i,j}\) 表示前 \(i\) 个物品总和为 \(j\) 的最大概率,直接跑背包。但是这样还仅仅是暴力。于是剪枝。首先概率为 \(100\) 的一定选,放到最后统一算贡献;首先概率为 \(0\) 的一定不选,直接忽略;但是这样还不够优秀。然后充分发扬人类智慧找找性质,或者依托强大的观察能力打表找规律,发现选中的东西不会很多。具体有多少,需要推式子。首先在最优状态下一定不会再多选或少选一个东西(废话)。然后对于概率相同的,一定选权值更大的更优。假设在当前概率 \(p\) 已经选了 \(i\) 个数,下一个选了会更优,也就是:

\[\begin{aligned} p^i \sum \limits_{j=1}^{i} w_j &\lt p^{i+1} \left ( \sum \limits_{j=1}^{i} w_j+w_{j+1} \right ) \\ \sum \limits_{j=1}^{i} w_j &\lt p \left ( \sum \limits_{j=1}^{i} w_j+w_{j+1} \right ) \end{aligned} \]

由于我们要贪心选大的,所以 \(w_{j+1}\) 一定不比之前任何一个数大,于是得到 \(j \times w_{j+1} \le \sum \limits_{j=1}^{i} w_j\),即 \(w_{j+1} \le \tfrac {\sum \limits_{j=1}^{i} w_j}{j}\)。带入原式,得:

\[\begin{aligned} \sum \limits_{j=1}^{i} w_j &\lt p \times \tfrac{(j+1) \times \sum \limits_{j=1}^{i} w_j}{j} \\ 1 &\lt p \times \tfrac{j+1}{j} \\ \tfrac{j}{j+1} &\lt p \\ j &\lt p \times j+p \\ (1-p) \times j &\lt p \\ j &\lt \tfrac{p}{1-p}\end{aligned} \]

于是就可以在这一步进行剪枝。只有满足上面条件的物品才可能被选中。拿个程序跑一下会发现这东西不大,378。但是我们 \(w\) 的值域依然很大。再次充分发扬人类智慧找找性质,或者依托强大的观察能力打表找规律,发现值域不会很大。设最优答案的权值和为 \(W\),概率为 \(P\),由于拿走一个答案一定会变得不优,继续根据答案单调性推式子:

\[\begin{aligned} W \times P &\gt (W-w_i)\times \tfrac{P}{p_i} \\ W &\gt \tfrac{(W-w_i)}{p_i} \\ W \times p_i &\gt W-w_i \\ W \times (p_i-1) &\gt -w_i \\ W \times (1-p_i) &\lt w_i \\ W &\lt \tfrac{w_i}{(1-p_i)} \end{aligned} \]

\(1-p_i\) 的最小值为 \(0.01\),\(w_i \lt 2\times 10^5\),推出来的这个结果貌似最大是 \(2 \times 10^7\) 的。但是由于 \(p_i \times w_i \le 2 \times 10^5\) 的(这个是输入的 \(p\),而分子取最大值时,\(p_i\) 取最小值,分母取到最大值;同理,分母取到最小值时分子取到最小值。不是很好分析,于是写个程序跑一下,发现最大值是 \(202020\),这样值域就是 \(2e5\) 量级的了。总复杂度为 \(378 \times 202020=76763560\),到了能跑的水平。

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,u,v,b;
vector<int>vec[101];
long double dp[220022],ans;
int main()
{
	scanf("%d",&a);
	for(ri i=1;i<=a;i++)
	{
		scanf("%d%d",&u,&v);
		vec[u].push_back(v);
	}
	vec[0].clear();
	for(ri i=1;i<=99;i++)
	{
		sort(vec[i].begin(),vec[i].end());
		reverse(vec[i].begin(),vec[i].end());
		while(vec[i].size()>100/(100-i))
		{
			vec[i].pop_back();
		}
	}
	vec[100].push_back(0);
	while(vec[100].size()>1)
	{
		vec[100][0]+=vec[100].back();
		vec[100].pop_back();
	}
	dp[0]=1;
	for(ri i=1;i<=99;i++)
	{
		for(ri j:vec[i])
		{
			for(ri k=200000;k>=j;k--)
			{
				dp[k]=max(dp[k],dp[k-j]*i/100);
			}
		}
	}
	for(ri i=0;i<=200000;i++)
	{
		ans=max(ans,dp[i]*(i+vec[100][0]));
	}
	printf("%.8Lf",ans);
	return 0;
}

标签:1000001,int,long,times,加赛,考试题,ri,NOIP2024,define
From: https://www.cnblogs.com/ywhhdjser-97/p/18538536

相关文章

  • NOIP2024模拟赛27 | 选手只有 T4 AC
    又是高一rk7。这场大众分太高了。我以为有很多人过T4的。80(95)+80+45(55)+100,sy机子太慢了。T1:场上只想出来\(A^{1/4}\log^2A\)的单次做法,只有80。即枚举小的那个底数。结论:满足条件的数可以表示成\(a^2b^3\)。???这样直接枚举\(\min(a,b)\le4000\)的质因子就做......
  • NOIP2024 前集训:NOIP2024加赛 3(欢乐赛)
    前言再次考古,现在才写。这场叫欢乐赛,搬的CF,不知道OJ哪儿来的RMJ。就记得T3一直往数据结构上想浪费好多时间,结果发现是结论题\(O(n)\)可做。T1SakurakoandWater虽然我之前不知道主对角线是什么东西,但是看完题目自动把他过滤成左上角到右下角了(不知道当时怎么想的,好......
  • NOIP2024 前集训:多校A层冲刺NOIP2024模拟赛20
    前言考古了,现在才写。已经忘了赛时历程了,就记得T1打了个错误率高达\(\dfrac{1}{100000}\)的乱搞做法(前后各连\(\log\)个\(k\)大值)然后被卡常了,后三道都没交不记得为啥了。T1星际联邦std是\(O(m\logm)\)的菠萝算法,但是被众人疯狂爆标。正解是\(O(n)\)的,不考虑......
  • 多校A层冲刺NOIP2024模拟赛21
    以为150要垫底了,没想到还有高手。送信卒签,没一会就写完但因为交的太晚被猫娘抢了首A。恼火。简要题意给一个\(n\timesm(n,m\le100)\)的网格图,左右走的代价为\(1\),上下走的代价为\(k\),求最小的\(k\),使得\((sx,sy)\)到\((tx,ty)\)的代价恰好为\(s(s\le10^5)\)。数据保证有解......
  • 『模拟赛』多校A层冲刺NOIP2024模拟赛21
    Rank别样的,不好评价,烂完了A.送信卒签,我是唐氏。为什么呢题目没给最短路的定义,我赛时觉得最短路就是最短路径,于是直接bfs一遍随便加个check就做完了。当然过得那遍按我的思路来说是错的,然后我也发现了这一点,然后就改了,然后就WA了。总结:错误思路的错解是正确思路......
  • 多校A层冲刺NOIP2024模拟赛21
    多校A层冲刺NOIP2024模拟赛21\(T1\)A.送信卒\(90pts/100pts\)部分分\(90pts\)设最后的可能的最短路中左右共移动了\(d\)次,上下共移动了\(x\)次。则等价于求\(\min\{x_{i}k+d_{i}\}=s\)的解,观察到\(d\in[0,\min(\left\lceil\frac{nm}{2}\right\rce......
  • NOIP2024模拟赛#18 总结
    头要炸了。T1题面很好懂,手玩了一下发现答案最小是\((m-1)\timesn\)。可能会多出来一个长度为\(k\)的部分,会发现如果多出来一个长度为\(k\)的部分且合法,那么单个串\(1\simk\)位与\(n-k+1\simn\)位一定相同,\(k+1\simn\)位与\(1\simn-k\)一定相同。Hash判一下即......
  • 『模拟赛』NOIP2024加赛4
    Rank给我唐完了,又名,【MX-S5】梦熊NOIP2024模拟赛1。A.王国边缘好像简单倍增就做完了。由于昨天T5在我脑海中留下了挥之不去的印象,今天一上来看到这题就发现是一个内向基环树森林。然后被硬控硬控硬控,最后一个小点加一点优化就能过没调出来,挂30pts,菜菜菜菜菜。注......
  • NOIP2024加赛4
    简评:搬的梦熊的,一签一难两不可做。王国边缘倍增板子(但我不会打倍增所以场上调了半天)。记\(f_{i,j}\)表示从\(i\)开始走\(2^j\)次时走的距离,\(g_{i,j}\)表示从\(i\)开始走\(2^j\)次时走到的点,这个用倍增。处理\(f_{i,0}\)和\(g_{i,0}\)时分讨即可,卡不卡常无所谓。时空复杂度\(O......
  • NOIP2024加赛4
    NOIP2024加赛4\(T1\)luoguP11267【MX-S5-T1】王国边缘\(85pts\)预处理前缀中最后一个\(1\)出现的位置然后就可以倍增跳了。点击查看代码constllp=1000000007;intnxt[200010][62],f[200010][62],last[200010];chart[200010];lldivide(lls,llk){llan......