• 多校第五场(字符串)


    5783.Divide the Sequence

    题意:给出一段序列,尽可能多得分割序列使得每段前缀和非负。


    分析:既然前缀和非负,那么从后往前遍历,若非负则++。


    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <time.h>
    #include <math.h>
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <map>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <bitset>
    using namespace std;
    
    #define LL long long
    #define F(i,a,b) for (int i=(a),_##i=(b); i<=_##i; i++)
    #define Rof(i,a,b) for (int i=(a),_##i=(b); i>=_##i; i--)
    #define rep(i,a,b) for (int i=(a),_##i=(b); i<=_##i; i++)
    #define rek(i,a,b) for (int i=(a),_##i=(b); i>=_##i; i--)
    #define mem(a,b) memset(a,b,sizeof(a))
    #define Cpy(a,b) memcpy(a,b,sizeof(b))
    int a[1001000],n;
    long long sum,m;
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(scanf("%d",&n)==1)
        {
            sum=m=0;
            F(i,1,n) scanf("%d",a+i);
            for(int i=n;i;--i)
            {
                m+=a[i];
                if(m>=0)
                {
                    sum++;m=0;
                }
            }
            printf("%I64d
    ",sum);
        }
        return 0;
    }

     5791.Two


    题意:给出两个数字序列,求两个序列的公共子序列的个数(可重复)


    分析:可dp,可用树状数组做。

    先给出dp方程,再解释.

    dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod;——1
    if(dp[i][j]<0) dp[i][j]+=mod;——2
    if(a[i]==b[j]) dp[i][j]=(dp[i][j]+dp[i-1][j-1]+1)%mod;——3

    第一个是每次都要使用的,因为dp[i][j]要加上除去a[i]的(dp[i-1][j]),加上除去b[j]的(dp[i][j-1],再减去重复加的(dp[i-1][j-1],就ok啦。

    第二个是保证dp[i][j]为正,因为在减dp[i-1][j-1]中可能为负,故要处理。

    最后是第三个,因为如果a[i]==b[j],那么对前面的所有都可加上a[i],b[j],所以要加一遍dp[i-1][j-1],然后a[i]和b[j]单独匹配得到,需要+1,

    举个例子:

    1 2 3 4 

    1 2

    匹配到2时,前面所有的匹配到的(1,1)都可变成(1 2,1 2)所以需要加一遍dp[i-1][j-1],ok啦。


    //jing miao de dong gui
    #include<cstdio>
    #include<cstring>
    const int mod=1000000007;
    int dp[1010][1010];
    int a[1010],b[1010],n,m;
    
    int main()
    {
        while(scanf("%d%d",&n,&m)==2)
        {
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;++i) scanf("%d",a+i);
            for(int i=1;i<=m;++i) scanf("%d",b+i);
            for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
            {
                dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1])%mod;
                if(dp[i][j]<0) dp[i][j]+=mod;
                if(a[i]==b[j]) dp[i][j]=(dp[i][j]+dp[i-1][j-1]+1)%mod;
            }
            printf("%d
    ",dp[n][m]);
        }
    }

    5792.World is Exploding

    题意:给出数字序列,找出满足某些条件的四个数的组数,Aa<Ab&&a<b,Ac>Ad&&c<d.


    分析:因为数字范围很大(达到1e9),而个数最多只有5万个,故要离散化。然后对每个数统计左边大于(l[])和小于(l1[])它的数,右边大于(r[])和小于(r1[])它的数。

    最后处理特殊情况,左边*右边-特殊情况就可以得到结果了,具体见BC的blog。


    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 5e4+7;
    int d[maxn],n,a[maxn],l[maxn],r[maxn],l1[maxn],r1[maxn];
    inline int lowbit(int x){
        return x&(-x);
    }
    //改点求段 
    inline void update(int x,int v){
        for(int i=x;i<maxn;i+=lowbit(i))
            d[i]+=v;
    }
    //d[1]~d[x] 
    inline int get(int x){
        int ans = 0;
        for(int i=x;i;i-=lowbit(i))
            ans+=d[i];
        return ans;
    }
    map<int,int>H;
    vector<int> V;
    int main(){
        while(scanf("%d",&n)!=EOF){
            fill(l1,l1+maxn-1,0);
            //memset(l1,0,sizeof(l1));
            memset(r1,0,sizeof(r1));
            memset(l,0,sizeof(l));
            memset(r,0,sizeof(r));
            memset(d,0,sizeof(d));
            V.clear();H.clear();
            for(int i=1;i<=n;i++)
            {
                scanf("%d",a+i);
                V.push_back(a[i]); 
            }
            sort(V.begin(),V.end());//排序 
            V.erase(unique(V.begin(),V.end()),V.end());//去重+翻转数列 
            //for(int i=0;i<n;i++) printf("%d ",V[i]);
            for(int i=0;i<V.size();i++)//hash? 
                H[V[i]]=i+1;
            for(int i=1;i<=n;i++)a[i]=H[a[i]];
    
            long long ans1=0,ans2=0,ans3=0;//树状数组求左边大于或小于它的数 
            for(int i=1;i<=n;i++){
                l[i]=get(a[i]-1);
                l1[i]=get(maxn-1)-get(a[i]);
                update(a[i],1);
            }
            memset(d,0,sizeof(d));
            for(int i=n;i>=1;i--){//更新加计算 右边大于或小于它的数 
                r[i]=get(a[i]-1);
                r1[i]=get(maxn-1)-get(a[i]);
                update(a[i],1);
            }
            for(int i=1;i<=n;i++) printf("l[i]=%d l1[i]=%d r[i]=%d rl[i]=%d
    ",l[i],l1[i],r[i],r1[i]); 
            for(int i=1;i<=n;i++){//统计 
                ans3+=1ll*l[i]*r[i];
                ans3+=1ll*l1[i]*r1[i];
                ans3+=1ll*l[i]*l1[i];
                ans3+=1ll*r[i]*r1[i];
                ans1+=l[i],ans2+=r[i];
            }
            cout<<ans1*ans2-ans3<<endl;//小的*大的-特殊情况
        }
    }
  • 相关阅读:
    牛哄哄的 汉诺塔递归
    c 终端控制
    ubuntu apt源
    vim 用法
    纯js 判断表单为空 阻止 input 提交
    Yii2 文本框前加图标 input 添加属性的方法
    layer 弹窗 弹出层 iframe子页面获取父级页面id
    获取Yii2 常用 路径 目录 url
    Yii Activeform 表单
    Yii use namespace 命名空间
  • 原文地址:https://www.cnblogs.com/chendl111/p/5734249.html
Copyright © 2020-2023  润新知