【substr + 逆序数+ 线段树push_up的位置!!!】2016 Multi-University Training Contest 4

慢慢补题路:
1001 Another Meaning

标程 KMP用的神乎其神,感觉掉的不行,但是没想到这题还可以用stl写,我也是醉了,只怪自己dp没学好,不过也算学到了另一种用法吧。
题意:
hehehehe
hehe
用模式串去匹配主串,模式串可能有两个意思,问主串最多有几个意思?
比如样例就是 3 个意思 hehehe” can have 3 meaings: “* he”, “he*”, “hehehe”.

先看一种stl

C++中substr函数的用法

#include<string>
 #include<iostream>
 using namespace std;

main()
 {
 string s("12345asdf");
 string a=s.substr(0,5);       //获得字符串s中 从第0位开始的长度为5的字符串//默认时的长度为从开始位置到尾
cout<<a<<endl;
 }
输出结果为:
12345

尼玛,早说有这种用法啊,我曹,那这道题就很简单了。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#define ll __int64
#define INF 0x7fffffff   //INT_MAX
#define inf 0x3f3f3f3f   //
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
using namespace std;
const int N = 100005;
const int MOD = 1000000007;

int T;
int n, m;
int dp[N];
string a,b;
int main() {
    scanf("%d", &T);
    int cas = 0;
    while (T--) {
        cin>>a>>b;
        dp[0] = 1;
        n=a.size();
        m=b.size();
        for (int i = 0; i < n; i++) {
            if(i>0)
                dp[i] = dp[i - 1];
            /* 如果这一位可以匹配
                 即a[i-m]-a[m] 可以和 b串匹配
            */
            string cnt;
            if(i+1-m>=0)
               cnt=a.substr(i+1-m,m);
            int flag=cnt==b?1:0;
            if (i+1-m>=0 && flag) {
                if(i+1==m)
                    dp[i]=2;
                else
                    dp[i] = (dp[i] + dp[i-m]) % MOD;
                //这种可能出现i-m <0  即第一组匹配会出错
                //我们特殊处理一下就行
            }
        }
        printf("Case #%d: %d\n", ++cas, dp[n-1]);
    }
    return 0;
}

这个题 当时粗略看了看,队友就过了
题意:
求冒泡排序(题中给出),某一个数 最左位置和最右位置的 差值。 随便推推不难发现,在这个排序中,其实求的就是每个数 后面的 比它小的数有多少个?因为,后面存在一个比他小的,他就会右移动, 但是当这个数最终位置在起始位置右边的时候,他肯定不会向左移动,哪怕前面有很多比它大的数。
所以这题就是求 每个数 后面的 比它小的数有多少个?= 前面比它大的数有多少个
换句话说:就是让我们求逆序数;

当年随意看了看n方 的方法,今天又想了许久,竟没有想出如何logn 做出来。惭愧!QAQ
学习了一下,感觉真是妙,自己真是菜。

序列
3  5  4  8  2  6  9
大体思路为:新建一个数组,将数组中每个元素置0
0  0  0  0  0  0  0
取数列中最大的元素,将该元素所在位置置1
0  0  0  0  0  0  1

统计该位置前放置元素的个数,为0

接着放第二大元素8,将第四个位置置1

0  0  0  1  0  0  1

统计该位置前放置元素的个数,为0

继续放第三大元素6,将第六个位置置1

0  0  0  1  0  1  1

统计该位置前放置元素的个数,为1

…

…

这样直到把最小元素放完,累加每次放元素是该元素前边已放元素的个数,这样就算出总的逆序数来了,或者每个元素的逆序数对有多少

统计个数,线段树即可完成
**特别注意一下 线段树 push_up的位置究竟 放在那里!!!!
改了很久的,这个很容易疏忽,一定要注意!!!!!!切记切记**
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<bitset>
#define mem(a) memset(a,0,sizeof(a))
#define ll __int64
#define INF 0x7fffffff   //INT_MAX
#define inf 0x3f3f3f3f   //
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
using namespace std;

struct seg{
    int l,r;
    int v;

}st[100005<<2];
void build(int l,int r,int rt){
    st[rt].v=0;
    st[rt].l=l;
    st[rt].r=r;
    if(l==r){
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt*2);
    build(mid+1,r,(rt<<1)+1);
}
void push_up(int rt){
    st[rt].v=max(st[rt].v,st[rt*2].v+st[(rt*2)+1].v);
    //应该取最大值,不取最大值,可能为0
}
void update(int p,int rt){
    if(st[rt].l==p && st[rt].r==p){
        st[rt].v=1;
        return ;
    }
    int mid=(st[rt].l+st[rt].r)/2;
    if(p<=mid){
        update(p,rt*2);
    }
    else
        update(p,(rt*2)+1);
    push_up(rt);            //连push_up的位置都不会放了??? 白学了!!!!
}
int qur(int l,int r,int rt){
    if(st[rt].l==l &&st[rt].r==r){
        return st[rt].v;
    }
    push_up(rt);
    int mid=(st[rt].l+st[rt].r)>>1;
    int ans=0;
    if(mid>=r){
        ans+=qur(l,r,rt<<1);
    }
    else if(l>mid){
        ans+=qur(l,r,(rt<<1)+1);
    }
    else{
        ans+=qur(l,mid,rt<<1);
        ans+=qur(mid+1,r,(rt<<1)+1);
    }
    return ans;
}
int a[100005];
int pos[100005];
int f[100005];
int main(){
    //freopen("1.txt","r",stdin);
    int t;
    scanf("%d",&t);
    int cas=1;
    while(t--){
        printf("Case #%d:",cas++);
        int n;
        scanf("%d",&n);
        build(1,n,1);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            pos[a[i]]=i;
        }
        for(int i=n;i>=1;i--){
            int cnt=qur(1,pos[i],1);   //i 前面比ai 大的
            cnt=n-pos[i] -(n-i-cnt);   // i后面比ai 小的
            int left,righ;
            left=min(pos[i],i);
            righ=pos[i]+cnt;
            f[i]=abs(left-righ);
            update(pos[i],1);
        }
        for(int i=1;i<=n;i++){
            printf(" %d",f[i]);
        }
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值