CSP2024 前集训:多校A层冲刺NOIP2024模拟赛12

前言

image

不理解为啥就打了这么点分。

T1 优化写错了只剩 \(b_i=1\) 部分分了,T2 脑瘫,以为两个同余方程加起来后会产生之前不合法现在合法的答案,遂没写 \(O(1)\) (实则为 \(O(\log)\))做法,T3 鉴定为不会二分图,T4 之前没听说过啥是迭代加深。

但是 T1 没过是我想不到的,怎么想赛时也不该不会啊。

T1 Alice 和璀璨花

做法很多。

可以直接跑 \(O(n^2)\) DP,发现这玩意可以数据结构优化,遂做完了。

可以类似与 \(O(n\log n)\) 求最长上升子序列做法直接维护,这个其实本来并不对,但是鉴于本题的特殊性他就是对的,和下面的做法本质上为同一个做法。

定义 \(f_{i,j}\) 表示处理到 \(a_i\),当前子序列长度为 \(j\) 是最后一个数的最小值,有转移:

\[f_{i,j}= \begin{cases} f_{i-1,j} &a_i\le f_{i-1,j-1}\times b_{j-1} \\ \min(f_{i-1,j},a_i) &a_i>f_{i-1,j-1}\times b_{j-1} \\ \end{cases}\]

发现对于固定 \(i\)\(f_{i-1,j}\) 是单调不下降的,不放找到一个点 \(k\),对于 \(j<k\) 的点满足 \(f_{i-1,j}<a_i\),这些数转移是没有意义的,因为一定 \(<a_i\);对于 \(j>k\) 的点也是无意义的,因为 \(f_{i-1,j-1}\times b_{j-1}\) 一定 \(\ge a_i\)

所以找到这个 \(k\),只转移这一个即可,复杂度 \(O(n\log n)\)

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e6+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,b[N]; ll a[N],f[N];
signed main()
{
	freopen("alice.in","r",stdin),freopen("alice.out","w",stdout);
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=n;i++) read(b[i]);
	memset(f,0x3f,sizeof(f)),f[0]=0;
	for(int i=1;i<=n;i++)
	{
		int j=lower_bound(f,f+i,a[i])-f;
		if(a[i]>f[j-1]*b[j-1]) f[j]=min(f[j],a[i]);
	}
	for(int i=n;i;i--) if(f[i]!=0x3f3f3f3f3f3f3f3f) return write(i),0;
}

T2 Bob 与幸运日

为了方便,这里的 \(a,b,x,y\) 实则为 \(a-1,b-1,x-1,y-1\),同于均是 \(\bmod w\) 意义上,后面懒得写了。

发现有 \(\begin{cases}dx+y\equiv a\\ dy+x\equiv b\end{cases}\),对其进行消元,有 \((d^2-1)x\equiv ad-b\)

那么对于 \(d^2-1\not\equiv 0\) 的情况就可以直接做了。

考虑怎么做 \(d_2-1\equiv 0\) 的情况,发现对于 \(d\equiv 1\) 的情况有 \(x+y\equiv a\)\(a\equiv b\)\(d\equiv -1\) 的情况有 \(x-y\equiv a\)\(a\equiv -b\)

发现可以根号分治,注意一些细节就做完了。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e6+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
ll T,n,m,d,w,a,b,x,y,ans;
inline ll qpow(ll a,ll b,ll p,ll res=1)
{for(;b;(a*=a)%=p,b>>=1) (b&1)&&((res*=a)%=p); return res;}
inline ll calc(ll x) {return n/w+(n%w>=x);}
signed main()
{
	freopen("bob.in","r",stdin),freopen("bob.out","w",stdout);
	for(read(T);T;T--)
	{
		read(m,d,w,a,b),n=min(m,d)-1,a--,b--,ans=0;
		if((d*d-1)%w)
		{
			x=(a*d-b+w)%w*qpow((d*d-1)%w,w-2,w)%w,y=(a-d*x%w+w)%w;
			write(calc(x)*calc(y)),puts("");
		}
		else if(d==w-1)
		{
			if(a!=w-b||n-a<0) {puts("0"); continue;}
			if(w<=3e4) for(ll x=0;x<=min(n,w-1);x++)
			{
				y=(a-x*d%w+w)%w;
				if((y*d%w+x+w)%w==b) ans+=calc(x)*calc(y);
			}
			else
			{
				ans=n<b?n-a+1:n;
				for(ll i=1;i<=(n-a)/w;i++) ans+=n-(i*w+a)+1;
			}
			write(ans),puts("");
		}
		else
		{
			if(a!=b) {puts("0"); continue;}
			if(w<=3e4) for(ll x=0;x<=min(n,w-1);x++)
			{
				y=(a-x*d%w+w)%w;
				if((y*d%w+x+w)%w==b) ans+=calc(x)*calc(y);
			}
			else for(ll i=0;i<=(n*2-a)/w;i++) ans+=min(2*n-i*w-a+1,i*w+a+1);
			write(ans),puts("");
		}
	}
}

T3 Charlie 的运输网

和我撞名了的题,但是我不会哈哈,咕了。

T4 David 与和谐号

直接迭代加深爆搜,发现答案 \(\le n\)

考虑估价函数怎么大打,且每次翻转只会改变一对相邻数对,那么对于一个状态求出相邻的差值 \(>1\) 的对数,还需要的步数一定大于这个值。

复杂度 \(O(能过)\)

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=30;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int T,n,ans,a[N][N],b[N];
inline int calc(int a[],int res=0)
{for(int i=2;i<=n;i++) if(abs(a[i]-a[i-1])>1) res++; return res;}
inline bool check(int a[])
{for(int i=1;i<=n;i++) if(a[i]!=i) return 0; return 1;}
inline void dfs(int x)
{
	if(x+calc(a[x])>=ans) return ;
	if(check(a[x])) return ans=x,void();
	for(int i=1;i<=n;i++) a[x+1][i]=a[x][i];
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=i;j++) b[j]=a[x][i-j+1];
		for(int j=1;j<=i;j++) a[x+1][j]=b[j];
		dfs(x+1);
		for(int j=1;j<=n;j++) a[x+1][j]=a[x][j];
	}
}
signed main()
{
	freopen("david.in","r",stdin),freopen("david.out","w",stdout);
	for(read(T);T;T--)
	{
		read(n); for(int i=1;i<=n;i++) read(a[0][i]);
		ans=n,dfs(0),write(ans),puts("");
	}
}
posted @ 2024-10-24 18:12  卡布叻_周深  阅读(33)  评论(6编辑  收藏  举报