• NOI 模拟赛


    咕了半年的 Meaningless Round 终于来了,好评

    虽然题目我一道都不会吧

    T1

    $n$ 个人排成一个环,轮流扔硬币,正面就出局,无论如何都给下一个人继续扔,求每个人留到最后的概率 $mod space 998244353$,硬币扔到正面的概率是 $frac{p}{q}$

    $n leq 5000$

    sol:

    容易发现当 $n=2$ 的时候就是一个收敛的无穷级数求和,但当 $n>2$ 的时候如果想要 dp,似乎怎么都绕不开无穷级数这个东西

    于是考场上自闭了,列了五六个错误的式子(甚至有一个只能过 $n=2$

    想了俩小时拿了 $0$ 分

    其实可以考虑高斯消元

    把规则换个方式描述就是:标号是一个圆盘,每次在 $1$ 号位置的人扔硬币,扔完圆盘旋转,如果扔的人出局,圆盘删掉一个标号

    这样我们可以设 $f_{(i,j)}$ 为剩下 $i$ 个人的时候,$j$ 号位置的人留到最后的概率

    讨论 $1$ 号位置是否出局,出局就是 $frac{p}{q} imes f_{(i-1,j-1)}$,没出局就是 $frac{p}{q} imes f_{(i,j-1)}$ 注意到这个式子里 $2 leq j leq i$,于是有了 $i-1$ 个方程,再加上最后一个 $sumlimits_{j=1}^i f_{(i,j)} = 1$(因为最后总会有一个人赢),就是每行 $i$ 个未知数 $i$ 个方程,可以高斯消元,总复杂度 $O(n^4)$

    事实上,考虑到每个转移总与上一行的数(已计算)和本行所有数有关,我们可以把每个 $f_{(i,j)}$ 都推成一个关于 $f_{(i,1)}$ 和上一行的数有关的式子,再用上文提到的“最后一个方程”把 $f_{(i,1)}$ 解出来,这样每行转移就是 $O(n)$ 的了

    总复杂度 $O(n^2)$

    T2

    定义字符串加法为把两个字符串拼起来,定义 $f(S)$ 为 $S$ 本质不同的子串的数量

    给一个字符串 $S$ 和 $q$ 组询问 $[l,r]$

    求 $sumlimits_{i=1}^{l-1} sumlimits_{j=r+1}^n f(S[1,i] + S[j,n])$

    $n,q leq 100000$

    sol:

    考试的时候完全不会,就瞎猜了个结论

    发现对于每次询问 $[l,r]$ 是在左边选一个前缀,右边选一个后缀(这里前后缀都可以为空)拼起来有多少本质不同的方案

    感性上理解一下,左右两边每有一个相同字符,答案就 $-1$,然后就是询问 $sumlimits_x get(1,l-1,x) imes get(r+1,n,x)$,其中 $get(l,r,x)$ 表示 $x$ 在 $[l,r]$ 中出现的次数

    咦,这不是 bzoj5016 吗,然后我傻了,还是差分成了 $4$ 个询问,其实一开始让 $r$ 在 $n+1$ 位置就可以不差分了

    但事实上 400000 组询问也在半秒钟内跑完了

    然后就莫名其妙过了

    #include<bits/stdc++.h>
    #define LL long long
    #define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
    #define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
    using namespace std;
    inline int read() {
        int x = 0,f = 1;char ch = getchar();
        for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
        for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
        return x * f;
    }
    const int maxn = 100010;
    int n,a[maxn];
    int bl[maxn],tot,cntl[maxn],cntr[maxn];
    LL ans[maxn];
    struct Ques {
        int l,r,flag,pos;
        Ques(){}
        Ques(int _1,int _2,int _3,int _4): l(_1),r(_2),flag(_3),pos(_4){}
        bool operator < (const Ques &b)const{return (bl[l] == bl[b.l]) ? (r < b.r) : (bl[l] < bl[b.l]);}
    }qs[maxn << 2];
    int qa[maxn], qb[maxn];
    int main() {
        freopen("B.in","r",stdin); freopen("B.out","w",stdout);
        n = read();
        for(int i=1;i<=n;i++)a[i] = read();
        int BLSIZE = sqrt(n);
        for(int i=1;i<=n;i++)bl[i] = i / BLSIZE;
        int q = read();
        for(int i=1;i<=q;i++) {
            int xl = 1,xr = read() - 1,yl = read() + 1,yr = n;
            qa[i] = xr + 1, qb[i] = yl - 1;
            qs[++tot] = Ques(xr,yr,1,i);
            if(xl > 1)qs[++tot] = Ques(xl - 1,yr,-1,i);
            if(yl > 1)qs[++tot] = Ques(xr,yl - 1,-1,i);
            if(xl > 1 && xr > 1)qs[++tot] = Ques(xl - 1,yl - 1,1,i);
        } sort(qs + 1,qs + tot + 1);
        int l = 0,r = 0;
        LL now = 0;
        for(int i=1;i<=tot;i++) {
            //if(qs[i].l > qs[i].r) continue;
            while(l < qs[i].l){l++;now += cntr[a[l]];cntl[a[l]]++;}
            while(r < qs[i].r){r++;now += cntl[a[r]];cntr[a[r]]++;}
            while(l > qs[i].l){cntl[a[l]]--;now -= cntr[a[l]];l--;}
            while(r > qs[i].r){cntr[a[r]]--;now -= cntl[a[r]];r--;}
            ans[qs[i].pos] += qs[i].flag * now; 
        }
        for(int i=1;i<=q;i++) printf("%lld
    ", 1LL * qa[i] * (n - qb[i] + 1) - ans[i]);
    }
    View Code

    T3

    给 $n$ 条直线和一个点 $(x,y)$ ,求这些直线所有交点中与 $(x,y)$ 距离前 $m$ 近的点与 $(x,y)$ 距离之和

    注意如果有 $k$ 条直线交于一点,这个交点将被算作 $inom{k}{2}$ 个点

    $n leq 10^5$

    sol:

    计算几何不会啊 qnq,结果考完发现是解析几何

    不仅 OI 退役文化课还要退役

    前 $m$ 近的点,我们可以二分一个半径 $R$ ,然后画一个圆把这 $m$ 个点包起来

    容易知道两条直线有有效的交点当且仅当它们都与圆有交点,且两条直线与圆交点按照一定方向(顺/逆时针)排好序之后是 $A_l,B_l,A_r,B_r$

    这个可以 dp 一下

  • 相关阅读:
    mycat 查询sql 报错
    mysql 主从 binlog
    数据库分库分表思路
    JavaScript数组知识
    JS判断当前页面是在 QQ客户端/微信客户端/iOS浏览器/Android浏览器/PC客户端
    js汉字转换为拼音
    工作中常用到的JS验证
    自动部署服务器代码
    php Excel 导入
    PHP 模拟http 请求
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10643038.html
Copyright © 2020-2023  润新知