• P1494 [国家集训队]小Z的袜子


    P1494 [国家集训队]小Z的袜子

    (洛谷没能交上去,就先放在博客里了)

    这是个模板题

    莫队的话,我学得别人,整了两个指针L和R

    然后每个询问得话,就是让我们求:

    从颜色相同的袜子里取两只的方案,然后再去除以这段从这段区间里随意取两只的方案

    这怎么处理呢?当然可以用组合数直接求出来

    而且,组合数只需要开C[N][3]就行,因为我们只需要穿两只袜子

    我感觉还是挺好想的,但是我看题解里没人发,我就发一份

    除了这个思路,其他基本都是模板,不会的话可以来我的博客

    或者这个大佬的博客

    #include <iostream>
    #include <cmath>
    #include <algorithm>
     
    using namespace std;
     
    const int N = 5e4 + 5;
     
    struct stu{
        int l,r;
        int id;
        int block;
        bool operator <(const stu &x) const {
            if(x.block == block)
                if(block % 2) return x.r < r;
                else return x.r > r;
            return x.block < block;
        }
            //莫队的普通排序,这样排更优
    }q[N];
     
    struct find_ans{
        long long son;
        long long mother;
    }ans[N];
     
    int l,r;
    int n,m;
    int v[N];
    int a[N];
    int cnt[N];
    long long cur_ans;
    long long C[N][4];
     
    void init()//预处理组合数
    {
        for(int i = 0;i <= n;i ++) C[i][0] = 1;
        for(int i = 1;i <= n;i ++)
            for(int j = 1;j <= 2;j ++)
                C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
     
    }
     
    void add(int pos)
    {
        cnt[a[pos]] ++;
        int x = cnt[a[pos]];
        cur_ans = cur_ans + C[x][2] - C[x - 1][2];
    }
     
    void del(int pos)
    {
        cnt[a[pos]] --;
        int x = cnt[a[pos]];
        cur_ans = cur_ans + C[x][2] - C[x + 1][2];
    }
     
    long long gcd_(long long x,long long y)
    {
        if(!y) return x;
        return gcd_(y,x % y);
    }
     
    find_ans ask()
    {
        long long this_ans,that_ans;
        this_ans = C[r - l + 1][2];//总的方案数,分母
        that_ans = cur_ans;
        long long gcd = gcd_(this_ans,that_ans);
        this_ans /= gcd;
        that_ans /= gcd;
        find_ans so_ans;
        so_ans.son = that_ans;
        so_ans.mother = this_ans;
        if(!this_ans) so_ans.mother = 1;
        return so_ans; 
    }
     
    int main()
    {
     
    //    freopen("8.in","r",stdin);
    //    freopen("88.out","w",stdout);
        cin >> n >> m;
        init();
        for(int i = 1;i <= n;i ++) cin >> a[i];
     
        int div = n / sqrt(m);
        for(int i = 1;i <= m;i ++)
        {
            int x,y;
            cin >> x >> y;
            if(x > y) swap(x,y);//这个地方坑死了,数据居然有l > r
            q[i].l = x;
            q[i].r = y;
            q[i].id = i;
            q[i].block = x / div;
            if(x == y)
            {
                ans[i].son = 0;
                ans[i].mother = 1;
                v[i] = 1;
                continue;
            }
        }
        sort(q + 1,q + 1 + m);
     
        l = 1,r = 0; 
        for(int i = 1;i <= m;i ++)
        {
            if(v[q[i].id]) continue;
            while(l < q[i].l) del(l ++);
            while(l > q[i].l) add(-- l);
            while(r < q[i].r) add(++ r);
            while(r > q[i].r) del(r --);
            ans[q[i].id] = ask();
        }
     
        for(int i = 1;i <= m;i ++)
            cout << ans[i].son << "/" << ans[i].mother << endl;
        return 0;
    }
    
  • 相关阅读:
    英文哲理短句
    经历的一次诈骗
    英文哲理短句
    反思对待新人的方式
    Java 开源报表制作
    现在开始写字
    关于Visual C++ 6.0的调试技巧和经验总结
    一步一步教你实现CTreeCtrl 自绘
    VC中动态加载ODBC解决方法
    VC++程序编译链接的原理与过程
  • 原文地址:https://www.cnblogs.com/xy0313/p/14073517.html
Copyright © 2020-2023  润新知