11.25 noip 模拟赛

T1 都不会 QwQ

T1

看出是找最长的等差数列

然后设 \(f_{i,j}\) 表示首项是 \(i\),公差是 \(j\)

写的是 \(O(nm)\)

然鹅只有 \(25\) 分,不知道为什么 WA 了

赛后听 lihe_qwq 说正解是枚举 \(k\),找出现最多的 \(b\)\(kx+b\)

然后复杂度是 \(O(\lfloor \frac{m}{n} \rfloor n)\)

因为 \(k\) 一定是整数

注意判上下界,赛时很多人挂分了

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define ll long long
#define fd(i,a,b) for(int i=(a);i<=(b);i=-~i)
#define bd(i,a,b) for(int i=(a);i>=(b);i=~-i)
#define endl '\n'
using namespace std;

inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x*f;
}

const int N=1e6+509,M=1e6+509,mod=998244353;

int n,m,a[N],ans;
unordered_map<int,int> f;

inline void init()
{
	n=read(),m=read();
	fd(i,1,n) a[i]=read();
	ans=0;
}

void solve(int k)
{
	f.clear();
	fd(i,1,n)
	{
		int b=a[i]-k*(i-1);
		if(b>0&&k*(n-1)+b<=m)
			++f[b],ans=max(ans,f[b]);
	}
}

inline void Main()
{
	init();
	fd(i,0,m/(n-1)) solve(i);
	printf("%lld\n",n-ans);
}

signed main()
{
	freopen("climb.in","r",stdin);
	freopen("climb.out","w",stdout);
	
	int T=read();
	while(T--) Main();
	
	return 0;
}

T2

码的 \(O(n^3)\) 的 DP

正解是发现如果交换,那么只有一列的 dp 值会改变

然后就变成 \(O(n^2)\)

T3

码的(理论上) \(O(n^3 \log n)\) 的 DP

最劣估计是 \(O(n^4)\),然鹅跑的飞快 (这就叫手法)

然后正解是把平方拆开发现是一个凸壳,然后维护即可

T4

码的 \(O(k \log n \log k)\) 线段树,但是因为数组开小 RE 了

喜提爆蛋

赛后改完交上去,居然有 \(35\)

正解是分块+线段树,听起来很麻烦

总结

  • 一道题如果枚举这个不行可以换另一个枚举,就比如今天的 \(kx+b\),枚举 \(b\)\(O(nm)\),而枚举 \(k\)\(O(\lfloor \frac{m}{n} \rfloor n)\)
  • 注意数据范围,数组要开够
posted @ 2024-11-25 15:45  whrwlx  阅读(11)  评论(0编辑  收藏  举报