CSP2024 前集训:多校A层冲刺NOIP2024模拟赛12
前言
不理解为啥就打了这么点分。
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\) 是最后一个数的最小值,有转移:
发现对于固定 \(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("");
}
}