20221109模拟赛题解

A

原题

分析

分类讨论。

对于 \(2\leq i\leq n\)

  1. \(a_i=a_{i-1}\),有 \(\dfrac{1}{a_i}\) 的概率选对。
  2. \(a_i>a_{i-1}\),有 \(\dfrac{a_{i-1}}{a_i}\cdot \dfrac{1}{a_{i-1}}=\dfrac{1}{a_i}\) 的概率选对。
  3. \(a_i< a_{i-1}\),有 \(\dfrac{a_i}{a_{i-1}}\cdot \dfrac{1}{a_i}=\dfrac{1}{a_{i-1}}\) 的概率选对。

最后特殊处理一下 \(1\) 然后求个和即可。

核心代码

const int MAXN=1e7+7;
int n,A,B,C,a[MAXN];double ans;
int main(){
    scanf("%d%d%d%d%d", &n, &A, &B, &C, a + 1);
    for (int i = 2; i <= n; i++)
        a[i] = ((long long) a[i - 1] * A + B) % 100000001;
    for (int i = 1; i <= n; i++)
        a[i] = a[i] % C + 1;
    ans+=1.0/qmax(a[n],a[1]);
    for(int i=2;i<=n;i++){
        ans+=1.0/qmax(a[i-1],a[i]);
    }printf("%.3lf\n",ans);
    return 0;
}

B

分析

弱化版是北大羟基的一道题。

有结论:

\(f(x)\)\(\R\) 上单调递增,设 \(M=\{x|f(x)=x\}\)\(N=\{x|f^{[n]}(x)=x\}\),则 \(M=N\)

证明:

\(S=\{x|f(x)=x\},T=\{x|f(f(x))=x\}\),用反证法容易证明 \(S\subseteq T\)

考虑证明 \(S=T\),即证 \(T\subseteq S\),即证 \(\forall x=f(f(x)),x=f(x)\)

继续用反证法,假设 \(\exist x=f(f(x)),x>f(x)\),由于 \(f(x)\) 是增函数,所以

\[x=f(f(x))<f(x) \]

,矛盾,假设不成立,\(x<f(x)\) 的情形同理。迭代次数更多时也可以这样证明。

观察题目给定的函数一定在 \(\R\) 上单调递增,利用上面的结论可将问题就转化成求 \(f(x)-x=0\) 的解。

观察发现 \(g(x)=f(x)-x\) 恒过 \((0,0)\),且在 \((-\infin,0)\) 有单峰,在 \((0,+\infin)\) 有单谷,三分找到峰点谷点后二分找零点即可。

核心代码

int n,m;
inline double f(double x){
    double res=0;
    for(int i=1;i<=2*m-1;i+=2) res+=pow(x,i);res/=(x+10);
    return res-x;
}int main(){
    qread(n,m);if(m==1) return puts("inf"),0;
    puts("3");double l=-10,r=0,mid,lmid,rmid;
    while(r-l>eps){
        mid=(l+r)*0.5;lmid=mid-eps;rmid=mid+eps;
        if(f(lmid)>f(mid)) r=mid;else l=mid;
    }r=l,l=-10;
    while(r-l>eps){
        mid=(l+r)*0.5;
        if(f(mid)>=eps) r=mid;else l=mid;
    }printf("%.6lf ",l);l=0;r=10;
    while(r-l>eps){
        mid=(l+r)*0.5;lmid=mid-eps;rmid=mid+eps;
        if(f(lmid)<f(mid)) r=mid;else l=mid;
    }r=10;
    while(r-l>eps){
        mid=(l+r)*0.5;
        if(f(mid)>=eps) r=mid;else l=mid;
    }printf("0 %.6lf\n",l);
    return 0;
}

C

原题

分析

首先考虑如何判断一个子段合法,这是个经典问题,\(dp_{i,0/1}\) 表示枚举到 \(i\)\(i\) 属于下降/上升子序列,上升/下降子序列的最小/最大值,直接转移即可。

此时枚举每一个子段,判断是否合法,时间复杂度 \(\mathcal O(n^3)\),期望得分 \(30pts\)

继续观察,发现若 \([l,r]\) 合法,那么 \([i,j](l\leq i\leq j\leq r)\) 一定合法,因为一个合法的子段删掉 LIS 后一定单调下降,而更小的子段就相当于删掉 LIS 中的一些元素,在删掉去掉 LIS 后剩下的一部分元素,一定合法。

于是可以分治地做,记录 \(f_i\) 表示以 \(i\) 开头的合法子段的最靠后的结尾,每次如果 \(f_l=f_r\) 就把整段赋成 \(f_l\),否则就计算 \(mid\)\(f\),再计算左半边和右半边。最后答案是 \(\sum f_i-i+1\)

核心代码

int n,a[MAXN],dp[MAXN][2],f[MAXN];
void cal(int x){
    dp[x][0]=0;dp[x][1]=n+1;
    for(int i=x+1;i<=n;i++){
        dp[i][0]=-1;if(a[i]<a[i-1]) dp[i][0]=dp[i-1][0];
        if(dp[i-1][1]!=-1&&dp[i-1][1]>a[i]) if(dp[i][0]==-1||dp[i][0]>a[i-1]) dp[i][0]=a[i-1];
        dp[i][1]=-1;if(a[i]>a[i-1]) dp[i][1]=dp[i-1][1];
        if(dp[i-1][0]!=-1&&dp[i-1][0]<a[i]) if(dp[i][1]==-1||dp[i][1]<a[i-1]) dp[i][1]=a[i-1];
        if(dp[i][0]==-1&&dp[i][1]==-1) return f[x]=i-1,void();
    }f[x]=n;
}void solve(int l,int r){
    if(l+1>=r) return;
    if(f[l]==f[r]){for(int i=l;i<=r;i++) f[i]=f[l];return;}
    int mid=(l+r)>>1;cal(mid);solve(l,mid);solve(mid,r);
}signed main(){
    qread(n);int i,j;for(i=1;i<=n;i++) qread(a[i]);cal(1);cal(n);int ans=0;solve(1,n);
    for(i=1;i<=n;i++) ans+=f[i]-i+1;printf("%lld\n",ans);
    return 0;
}

D

原题

分析

根据库默尔定理,\(n+m\choose m\) 所含 \(p\) 的幂次数 \(p\) 进制下 \(n+m\) 的进位数。

证明:

\(vp(n)\)\(n\)\(p\) 的次数,则

\[vp({n+m\choose m})=\sum\limits_{i=1}^\infin \left\lfloor \frac{n+m}{p^i} \right\rfloor- \left\lfloor \frac{n}{p^i} \right\rfloor- \left\lfloor \frac{m}{p^i} \right\rfloor \]

,也就是 \(p\) 进制下 \(n+m\) 的进位数,然后就转化成了求满足 \(0\leq n+k\leq A\)\(n+k\) 进位数 $ \geq \alpha$ 的方案数。

定义状态 \(dp_{i,j,0/1,0/1}\) 表示前 \(i\) 位,共进 \(j\) 次,取满/没取满,前一位没进位/进位的方案数。大分类讨论转移即可。

posted @ 2022-11-09 13:37  l_x_y  阅读(27)  评论(0编辑  收藏  举报