zoukankan      html  css  js  c++  java
  • 2021“MINIEYE杯”中国大学生算法设计超级联赛(10)

    2021“MINIEYE杯”中国大学生算法设计超级联赛(10)

    庆祝暑期训练赛结束了

    Pty loves lines

    • 题意

    (n)条直线,求直线相交的所有可能的交点数情况并输出。

    • 思路

    首先,每条直线最极端情况(所有直线不平行),那么就有(frac{(n * (n - 1))}{2})个交点。
    之后,我们先管直线的平行情况。

    1. 所有直线相交,即0(所有(n)都存在的一种情况)
    2. (n - 1)条直线平行,即(1 * (n - 1) = n - 1),一种
    3. (n - 2)条直线平行,那么另外两条直线可以平行,也可以相交,那么答案为: (2 * (n - 2) + 0 or 2 * (n - 2) + 1)两种。
    4. (n - 3)条直线平行,那么看另外三条直线((0,2,3) + (3 * (n - 3)))
      之后其实都差不多,那么我们也可以发现第四种情况的时候,看另外三条直线的情况,其实左边那部分就是(n = 3)时的情况,后面在推也一样,那么通过这个性质就可以求递推公式,然后用(dp)进行状态转移即可。
      定义(f[i][j])表示(i)条直线,(j)个交点的情况是否可以,((f[i][j])为1或0),那么(f[i][j] = f[i - k][j + (k * (i - k))]),就类似我上面的递推,然后(O(n^4))打表程序就出来了0.0,其实我们发现这个性质后就应该想到可以用bitset加一层优化,然后通过打表可以发现,一大段数字在后面都是连续的不用管(最多在30000多那就一直连续了,这个连续的最大值也可以打表求出来),那么就可以直接暴力点不管那后面的,那么就可以随便跑了(O(n * n * 32000 / w))

    code :

    const int N = 710, M = 32000;
    
    bitset<M> f[N];
    
    void init() {
        f[0][0] = 1;
        fep(i,1,700) {
            fep(k,1,i) {
                f[i] |= f[i - k] << (k * (i - k));
            }
        }
    }
    
    void solve(){
        int n;
        cin >> n;
        int limit = min(M - 1, n * (n - 1) / 2);
        bool flag = 0;
        for(int i = 0;i <= limit;i ++){
            if(f[n][i]) {
                if(flag) cout << ' ';
                else flag = 1; 
                cout << i;
            } 
        }  
        for(int i = limit + 1;i <= (n * (n - 1) / 2);i ++) {
            cout << ' ' << i;
        }
        cout << endl;
    }
    

    Pty loves string

    • 题意

    给一个字符串(S),共(Q)次询问,问字符串(S)中长度为(l)的前缀 + 长度为(r)的后缀形成的字符串在(S)中出现的次数。

    • 思路

    (kmp)找到字符串中长度相同的子串,前后都跑一边,那么长度为(l),到某个点(x)(1 o l = x o x + l - 1),点y,(n - r o n = y - r + 1 o y),然后就是判断(y - r + 1 = x + l)的点即可,然后就是找一点(z)(1 o l = z - l + 1 o z and n - r o n = z o z + r - 1),存在即答案加1,可以看出建图跑比较方便。
    然后建两棵树的图即可,随意用一颗树的dfs序在另一颗树上跑主席树,可持久化记忆。然后每次查询即可

    code :

    int in[N][2], out[N][2], tot[2], pos[N];
    int rt[N];
    int ls[N << 8],rs[N << 8],sum[N << 8], idx;
    char str[N];
    int f1[N],f2[N];
    int kkk;
    int h1[N],e1[N],ne1[N],m1, h2[N], e2[N],ne2[N], m2;
    
    void ad1(int a,int b) {
        e1[m1] = b, ne1[m1] = h1[a], h1[a] = m1 ++;
    }
    
    void ad2(int a,int b) {
        e2[m2] = b, ne2[m2] = h2[a], h2[a] = m2 ++;
    }
    void dfs1(int u)
    {
        in[u][0] = ++ tot[0];
        pos[tot[0]] = u;
        for(int i = h1[u];~i;i = ne1[i]) {
            int j = e1[i];
            dfs1(j);
        }
        out[u][0] = tot[0];
    }
    void dfs2(int u) {
        in[u][1] = ++ tot[1];
        for(int i = h2[u];~i;i = ne2[i]) {
            int j = e2[i];
            dfs2(j);
        }
        out[u][1] = tot[1];
    }
    
    void insert(int &t,int pre,int l,int r,int x) {
        t = ++ idx;
        ls[t] = ls[pre]; rs[t] = rs[pre];
        sum[t] = sum[pre] + 1;
        if(l == r) {return;}
        int mid = l + r >> 1;
        if(x <= mid) insert(ls[t],ls[pre],l,mid,x);
        else insert(rs[t],rs[pre],mid + 1,r,x);
    }
    
    int query(int p,int q,int l,int r,int x,int y) {
        if(r < x || y < l) return 0;
        if(x <= l && r <= y) return sum[p] - sum[q];
        int mid = l + r >> 1;
        return query(ls[p],ls[q],l,mid,x,y) + query(rs[p],rs[q],mid + 1,r,x,y);
    }
    
    void solve(){
        int n,q;
        cin >> n >> q;
        cin >> (str + 1);
        // 字符串kmp预处理
        int j = 0;
        memset(h1,-1,sizeof h1);
        memset(h2,-1,sizeof h2);
        for(int i = 2;i <= n;i ++) {
            while(j && str[j + 1] != str[i]) j = f1[j];
            if(str[j + 1] == str[i]) j ++;
            f1[i] = j;
        }
        j = n + 1;
        f2[n] = n + 1;
        for(int i = n - 1;i >= 1;i --) {
            while(j <= n && str[j - 1] != str[i]) j = f2[j];
            if(str[j - 1] == str[i]) j --;
            f2[i] = j;
        }
        // 建树
        for(int i = 1;i <= n;i ++) {
            ad1(f1[i],i);
            ad2(f2[i],i);
        }
        dfs1(0);
        dfs2(n + 1);
        // 处理
        for(int i = 1;i <= n + 1;i ++) { // 注意我们的dfs序是从0或n + 1开始的,所以需要加1
            insert(rt[i], rt[i - 1],1,n + 1,in[pos[i] + 1][1]);
        }
        while(q --) {
            int x,y;
            cin >> x >> y;
            y = n - y + 1;
            cout << query(rt[out[x][0]],rt[in[x][0] - 1],1,n + 1,in[y][1],out[y][1]) << endl;
        }
        for(int i = 0;i <= n + 1;i ++) f1[i] = f2[i] = 0, rt[i] = 0;
        idx = tot[1] = tot[0] = 0;
        m1 = m2 = 0;
    }
    
    
  • 相关阅读:
    Android中Context具体解释 ---- 你所不知道的Context
    JDK6、Oracle11g、Weblogic10 For Linux64Bit安装部署说明
    matplotlib 可视化 —— 定制 matplotlib
    matplotlib 可视化 —— 移动坐标轴(中心位置)
    matplotlib 可视化 —— 移动坐标轴(中心位置)
    matplotlib 可视化 —— 定制画布风格 Customizing plots with style sheets(plt.style)
    matplotlib 可视化 —— 定制画布风格 Customizing plots with style sheets(plt.style)
    指数函数的研究
    指数函数的研究
    指数分布的研究
  • 原文地址:https://www.cnblogs.com/darker-wxl/p/15165963.html
Copyright © 2011-2022 走看看