• Codeforces Round #404 (Div. 2) C 二分,水 D 数学,好题 E 分块


    Codeforces Round #404 (Div. 2)

    C. Anton and Fairy Tale

    题意:仓库容量n,每天运来m粮食,第 i 天被吃 i 粮食,问第几天仓库第一次空掉。

    tags:==SB题   注:二分边界判断,数据范围爆long long判断。

    // CF404 C
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    typedef long long ll;
    const int N = 200005;
    
    ll n, m;
    int main()
    {
        cin>>n>>m;
        if(n<=m) return 0*printf("%lld
    ", n);
        ll l=m+1, r=2e18, ans;        //边界 
        while(l<=r) {
            ll mid=l+((r-l)>>1);
            if(mid-m>2e9) {            //判断爆long long 
                r=mid-1, ans=mid;
                continue;
            }
            ll s1=n-m, s2=((mid-m)*(1+mid-m))>>1;
            if(s1<=s2) r=mid-1, ans=mid;
            else l=mid+1;
        }
        printf("%lld
    ", ans);
    
        return 0;
    }
    View Code

    D. Anton and School - 2

    题意:一个字符串 s,只包含小括号'('和')'。定义长度为len的RSBS序列:1、len不为0且为偶数。2、前一半的字符都是'(',后一半的字符都是')'。  问s 有多少个子序列是RSBS序列

    tags: 好题

    1、首先总体思路要正确,即要想到根据1~len-1个分界线来求。所以先枚举求出每个分界线左边有 l[i]个左括号,右边有 r[i]个右括号。 

    2、为了不重复,只选择左边第一个恰好是左括号的分界线计算。比如到了第 i 条分界线且分界线左边第一个恰好是左括号,则为了不重复这个左括号必须选,然后在 l[i]-1 个左括号中选 j 个,在r[i]个右括号中选 j+1 个。 

    3、 ans= , 因为i<=l[i]-1,且i+1<=r[i],所以可取k=r[i]-1。由范德蒙恒等式则ans=

    4、逆元求组合数。

    // CF404  D
    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    typedef long long ll;
    const int N = 200005, mod=1000000007;
    
    char s[N];
    int l[N], r[N], len;
    ll sum, fac[N], inv[N];
    ll fpow(ll a, int b) {ll ans=1; for(;b;a=a*a%mod,b>>=1)if(b&1)ans=ans*a%mod; return ans;}
    ll Inv(ll x) {return fpow(x, mod-2);}
    ll C(int a, int b) 
    { 
        if(b==0 || a==b) return 1;
        return fac[a]*inv[b]%mod*inv[a-b]%mod;
    }
    int main()
    {
        scanf("%s", s+1);
        len=strlen(s+1);
        rep(i,1,len-1) l[i]=l[i-1]+ (s[i]=='('?1:0);
        per(i,len-1,1) r[i]=r[i+1]+ (s[i+1]==')'?1:0);
        
        fac[0]=1;
        rep(i,1,len) fac[i]=fac[i-1]*i%mod, inv[i]=Inv(fac[i])%mod;        //求组合数预处理优化,inv[i]表示i的阶乘的逆元 
        
        rep(i,1,len-1) if(s[i]=='(') {
            sum=(sum+C(l[i]+r[i]-1, r[i]-1))%mod;    
        }
        printf("%lld
    ", (sum+mod)%mod);
    
        return 0;
    }
    View Code

    E. Anton and Permutatio

    题意:n个数的序列a[],有q个询问。每次询问有 l、r,交换a[l]和a[r]的值,求[l, r]区间的逆序数对数。

    tags:第一次搞分块,好暴力,,看了题解强行码出来的==

    对于区间问题,且不好用线段树或树状数组的情况,可以考虑分块做。

    主要思路是:交换a[l]、a[r]后, 区间[0,l-1]和[r+1,n-1]的不用考虑。而[l, r]的,看有多少>a[l]或<a[r]的,和有多少<a[l]或>a[r]的,更新ans。     这题,分好块后,对两边单独的两块直接扫;对于中间的每一块,二分解决。    在更新块时,也同样是二分来实现块中有序插入和删除a[l]、a[r] 。

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    #define ALL(x) x.begin(),x.end()
    typedef long long ll;
    const int N = 200005, M=500;
    
    int n, q, a[N];
    int st[M], ed[M], l, r, idl, idr, col;
    ll ans;
    vector<int >b[M];
    void Init()
    {
        scanf("%d %d", &n, &q);
        //分块 
        col=(int)sqrt(n);  //块大小 
        rep(i,0,n/col-1) st[i]=col*i, ed[i]=col*(i+1);     //标号是从 0开始的, 注意
        if(n%col) st[n/col]=n-(n%col), ed[n/col]=n;
        
        rep(i,0,n-1) {
            a[i]=i;
            b[i/col].push_back(i);
        }
    }
    void update()
    {
        if(idl<idr) {    // 二分更新数据 ,实现 vector的有序插入、删除 
            b[idl].erase(lower_bound(ALL(b[idl]), a[l]));    
            b[idl].insert(lower_bound(ALL(b[idl]), a[r]), a[r]);
            b[idr].erase(lower_bound(ALL(b[idr]), a[r]));
            b[idr].insert(lower_bound(ALL(b[idr]), a[l]), a[l]);
        }
        if(a[l]<a[r]) ans++; else ans--;
        swap(a[l], a[r]);
    }
    void solve()
    {
        scanf("%d %d", &l, &r);
        l--, r--;
        if(l==r) { printf("%lld
    ", ans); return ;}
        if(l>r) swap(l, r);
        idl=l/col, idr=r/col;
        //对中间块每一块二分 
        rep(i,idl+1,idr-1) {
            int Size=b[i].size();
            int p=lower_bound(ALL(b[i]), a[l])-b[i].begin();
            ans-=p, ans+= Size-p;
            p=lower_bound(ALL(b[i]), a[r])-b[i].begin();
            ans+=p, ans-= Size-p;
        } 
        //对两边的单独两块,直接暴扫 
        for(int i=l+1; i<ed[idl] && i<r; i++) {
            if(a[i]>a[l]) ans++; else ans--;
            if(a[i]>a[r]) ans--; else ans++;
        }
        for(int i=st[idr]; i<r && l<i; i++) {
            if(a[i]>a[l]) ans++; else ans--;
            if(a[i]>a[r]) ans--; else ans++;
        }
        
        update();
        printf("%lld
    ", ans);
    }
    int main()
    {
        Init();
        while(q--) {
            solve();
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    Google app engine python 2.5.4 安装ssl
    Ubuntu 10.04分辨率
    Google Voice 国内用户开通全攻略(图文)
    (linux)查看及修改文件权限以及相关
    InstallAnyWhere使用笔记制作升级补丁时的一些判断
    openoffice 编译依赖关系履历
    匹配连续的任意字词
    BT3 无线密码
    All roads lead to Rome, some smooth, some rough.
    test
  • 原文地址:https://www.cnblogs.com/sbfhy/p/6575246.html
Copyright © 2020-2023  润新知