Live2d Test Env

【几个区间问题】

大概是需要前缀和优化DP,和记录左右范围。

还有一道题,没有下手,等做完了,再来总结。

 

1,数组分拆: 给定数组,问有多少种拆分法,使得每一段和不为0。 (1e5)

 (用map优化DP)

#include<map>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int Mod=1e9+7;
const int maxn=100010;
map<int,int>mp;
int dp[maxn],sum[maxn],Now=1;
int main()
{
    int n,i,j;
    Now=1; mp[0]=1;
    scanf("%d",&n);
    for(i=1;i<=n;i++) scanf("%d",&sum[i]),sum[i]+=sum[i-1];
    for(i=1;i<=n;i++){
        dp[i]=Now;
        int tmp=0;
        if(mp.find(sum[i])!=mp.end()) tmp=mp[sum[i]]%Mod;
        dp[i]=((dp[i]-tmp)%Mod+Mod)%Mod;
        Now=(Now+dp[i])%Mod;
        mp[sum[i]]=(mp[sum[i]]+dp[i])%Mod;
    }
    printf("%d\n",dp[n]%Mod);
    return 0;
}
View Code

 

2,数组区间: 求所有区间前k大的和。 (1e5,k<=50)

(枚举每个数的的左右端点,我用的暴力,还可以优化)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn=2000010;
ll ans,x[maxn],n,k,L[60],R[60];
void getL(ll u)
{
    memset(L,0,sizeof(L));
    ll tmp=1; L[tmp]=u;
    for(ll i=u-1;i>=1;i--){
        if(x[i]<x[u]) L[tmp]=i;
        else L[++tmp]=i;
        if(tmp>51) break;
    }
}
void getR(ll u)
{
    memset(R,0,sizeof(R));
    ll tmp=1; R[tmp]=u;
    for(ll i=u+1;i<=n;i++){
        if(x[i]<x[u]) R[tmp]=i;
        else R[++tmp]=i;
        if(tmp>51) break;
    }
}
int main()
{
    scanf("%lld%lld",&n,&k);
    for(ll i=1;i<=n;i++) scanf("%lld",&x[i]);
    for(ll i=1;i<=n;i++){
        getL(i);
        getR(i);
        for(ll j=1;j<=50&&L[j];j++)
         for(ll p=1;p<=50&&R[p];p++){
             if(j+p-2<k){
                 ll tmp1=L[j-1],tmp2=R[p-1];
                 if(tmp1==0) tmp1=i+1;
                 if(tmp2==0) tmp2=i-1;
                 ans+=(ll)(tmp1-L[j])*(R[p]-tmp2)*x[i];
             }
         }
    }
    
    printf("%lld\n",ans);
    return 0;
}
View Code

 

3,数组分拆II:给定数组,问有多少种拆法,使得每一段不出现重复的数字,且要保证分组数最少。(1e5)

(和第一题有些像,只要快速找到前面的最大限制即可)

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
const int Mod=1000000007;
int a[maxn],d[maxn],dp[maxn],sum[maxn];
int Laxt[maxn],pre[maxn],Fir[maxn],L,Now;
int main()
{
    int i,j,n;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
       scanf("%d",&a[i]);
       if(Laxt[a[i]]) pre[i]=Laxt[a[i]];
       Laxt[a[i]]=i;
    }        
    for(i=1;i<=n;i++){
        if(pre[i]>L) L=pre[i];
        d[i]=d[L]+1;
        if(!Fir[d[i]]) Fir[d[i]]=i;
    }
    L=0; Now=0;
    for(i=1;d[i]==1;i++) dp[i]=1,sum[i]=i;
    for(;i<=n;i++){
        if(d[i]!=Now) {
            L=Fir[Now];
            Now=d[i];
        }
        L=max(L,pre[i]);
        dp[i]=((sum[Fir[Now]-1]-sum[L-1])%Mod+Mod)%Mod;
        sum[i]=(sum[i-1]+dp[i])%Mod;
    }
    printf("%d %d\n",d[n],dp[n]);
    return 0;
}
View Code 

 

4,有趣的子区间:给定a<=b求,问有多少对p,q,满足a<=p<=q<=b,使得区间[p,q]是有趣区间。有趣区间是指包含偶数个回文数。(1e10)

 

5,区间价值: 区间的价值定理为有多少对相同元素,问所有区间里,第k小区间价值是多少。

(利用单调性可以使用二分法,check的时候想双指针一样扫描)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int maxn=200010;
ll a[maxn],b[maxn],vis[maxn],cnt,N,K;
bool check(ll x)
{
    memset(vis,0,sizeof(vis));
    ll sum=0, ans=0;
    for(int tail=1,head=1;head<=N;head++){
        while(tail<=N&&sum+vis[a[tail]]<=x){
            sum+=vis[a[tail]];
            vis[a[tail]]++;
            tail++;
        }
        ans+=tail-head;
        if(ans>=K) return true;
        vis[a[head]]--;
        sum-=vis[a[head]];
    }
    return false;
}
int main()
{
    ll T,L,R,Mid,ans;
    scanf("%lld",&T);
    while(T--){
        scanf("%lld%lld",&N,&K);
        for(int i=1;i<=N;i++){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        sort(b+1,b+N+1);
        cnt=unique(b+1,b+N+1)-(b+1);
        for(int i=1;i<=N;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
        L=0;  R=N*(N-1)/2;
        while(L<=R){
            Mid=(L+R)/2;
            if(check(Mid)) ans=Mid,R=Mid-1;
            else L=Mid+1;
        }
        printf("%lld\n",ans);
    } return 0;
}
View Code

 

posted @ 2018-02-18 18:07  nimphy  阅读(314)  评论(0编辑  收藏  举报