CodeForces 1167 E.Range Deleting & F.Scalar Queries

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

Catalog

Problem:传送门

Portal
 原题目描述在最下面。


E.Range Deleting

  • 题意:
    给你一段长度为 n n n值域为 [ 1 , m ] [1, m] [1,m]的序列, n , m ≤ 1 e 6 n,m\le 1e6 n,m1e6
    问有多少对 p a i r ( l , r ) pair(l,r) pair(l,r)满足,原序列删除值在 [ l , r ] [l,r] [l,r]范围内的数字后,序列单调不递减。

  • 观察:
    如果原序列本来就单调不递减,那答案就是 m ∗ ( m + 1 ) / 2 m*(m+1)/2 m(m+1)/2
    l s [ x ] ls[x] ls[x]表示值 x x x第一次出现的位置, r s [ x ] rs[x] rs[x]表示值 x x x最后一次出现的位置。
    若序列本来不是单调不递减,就是存在 a , b a,b a,b满足: 1 ≤ a &lt; b ≤ m , r s [ a ] &gt; l s [ b ] 1\le a\lt b\le m,rs[a]\gt ls[b] 1a<bm,rs[a]>ls[b]
    我们找到第一次出现矛盾的值 x x x和最后一次出现矛盾的值 y y y。即 r s [ x − 1 ] &gt; l s [ x ] rs[x-1]\gt ls[x] rs[x1]>ls[x] r s [ y ] &gt; l s [ y + 1 ] rs[y]\gt ls[y+1] rs[y]>ls[y+1]
    观察可知: p a i r ( l , r ) pair(l,r) pair(l,r)必须满足: l ≤ x &ThickSpace; ∣ ∣ &ThickSpace; r ≥ y l\le x\;||\;r\ge y lxry

  • 解析:
    从上面我们得到了 p a i r ( l , r ) pair(l,r) pair(l,r) l l l的上界和 r r r的下界。
    考虑枚举 r r r,找到能满足条件的最大的 l l l,那么剩下的 1 , 2 , . . . , l − 1 1,2,...,l-1 1,2,...,l1做左端点肯定也是满足条件的 p a i r pair pair。这个道理应该很明显。
    显然如果你从大到小的枚举 r r r,他们满足条件的最大的 l l l肯定是单调不递增的。
    然后就随便 O ( n ) O(n) O(n)计数了。就这样找 l l lwhile(rs[x-1] > ls[i+1]) -- x;
    因为你只要知道删除 p a i r ( l , r ) pair(l,r) pair(l,r)后,能满足 r s [ l − 1 ] &lt; l s [ r + 1 ] rs[l-1]\lt ls[r+1] rs[l1]<ls[r+1]即可。

  • 细节:
    因为有的数字没有出现过,所以找 x , y x,y x,y的时候,先离散化一下在找比较方便。
    比如: 3 3 3 1 1 1。没有出现 2 2 2,这时候 x = 3 , y = 1 x=3,y=1 x=3,y=1。因为 r s [ 1 ] &gt; l s [ 3 ] rs[1]\gt ls[3] rs[1]>ls[3]
    还有就是对于没出现过的数字他的 l s [ ] 和 r s [ ] ls[]和rs[] ls[]rs[]怎么赋值呢?
    因为在算答案贡献的时候,只关心小数字的 r s [ ] rs[] rs[]和大数字的 l s [ ] ls[] ls[]
    所以对不存在的数就: r s [ x ] = r s [ x − 1 [ , l s [ x ] = l s [ x + 1 ] rs[x]=rs[x-1[,ls[x]=ls[x+1] rs[x]=rs[x1[,ls[x]=ls[x+1]
  • 总结:
    只要你发现了那个观察,这个题就是一个傻逼题啊。
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define eb emplace_back
#define o2(x) (x)*(x)
#define all(x) (x).begin(), (x).end()
#define BASE_MAX 62
#define debug(x) cout << "[" << x << "]\n"
#define endl "\n"
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
inline LL read(){
  LL x=0;int f=0;char ch=getchar();
  while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
  while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
  return x=f?-x:x;
}
inline void write(LL x) {
    if(x==0){putchar('0'),putchar('\n');return;}
    if(x < 0) {putchar('-');x=-x;}
    static char s[23];int l = 0;
    while(x!=0)s[l++]=x%10+48,x/=10;
    while(l)putchar(s[--l]);
    putchar('\n');
}
template<class T>T Max(T a1,T a2){ return a1>a2?a1:a2; }
template<class T>T Max(T a1,T a2,T a3){ return Max(a1,Max(a2,a3)); }
template<class T>T Max(T a1,T a2,T a3,T a4){ return Max(a1,a2,Max(a3,a4)); }
template<class T>T Min(T a1,T a2){ return a1<a2?a1:a2; }
template<class T>T Min(T a1,T a2,T a3){ return Min(a1,Min(a2,a3)); }
template<class T>T Min(T a1,T a2,T a3,T a4){ return Min(a1,a2,Min(a3,a4)); }
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int HMOD[] = {1000000007, 1000000009};
const LL BASE[] = {1572872831, 1971536491};
const int MXN = 1e6 + 7;

int n, m;
int ar[MXN];
int ls[MXN], rs[MXN];
int main() {
    n = read(), m = read();
    std::vector<int> vs; vs.eb(0);
    for(int i = 1; i <= n; ++i) ar[i] = read(), rs[ar[i]] = i, vs.eb(ar[i]);
    for(int i = n; i >= 1; --i) ls[ar[i]] = i;
    ls[m+1] = n+1;
    for(int i = 2; i <= m; ++i) if(rs[i] == 0) rs[i] = rs[i-1];
    for(int i = m; i >= 1; --i) if(ls[i] == 0) ls[i] = ls[i+1];
    //for(int i = 0; i <= m + 1; ++i) printf("%d %d*\n", ls[i], rs[i]);
    int x = -1, y = -1;
    sort(all(vs)); vs.erase(unique(all(vs)), vs.end());
    for(int i = 1; i < vs.size(); ++i) if(ls[vs[i]] < rs[vs[i-1]]){
        x = vs[i]; break;
    }
    for(int i = vs.size()-2; i >= 0; --i) if(rs[vs[i]] > ls[vs[i+1]]){
        y = vs[i]; break;
    }
    //printf("%d %d\n", x, y);
    if(x == -1) {
        write((LL)m*(m+1)/2);
        return 0;
    }
    LL ans = 0;
    for(int i = m; i >= y; --i) {
        while(rs[x-1] > ls[i+1]) -- x;
        ans += x;
        //debug(x);
    }
    write(ans);
    return 0;
}

F.Scalar Queries

  • 题意:
    ∑ 1 ≤ l ≤ r ≤ n f ( l , r ) \sum_{1\le l\le r\le n}f(l,r) 1lrnf(l,r) f ( l , r ) = ∑ i = 1 r − l + 1 i ∗ a r [ i ] f(l,r)=\sum_{i=1}^{r-l+1} i*ar[i] f(l,r)=i=1rl+1iar[i],数组 a r ar ar是把原数组的 [ l , r ] [l,r] [l,r]部分从小到大排序后得到的新数组。
  • 人尽皆知:
    首先 ∑ 1 ≤ l ≤ r ≤ n g ( l , r ) \sum_{1\le l\le r\le n}g(l,r) 1lrng(l,r) g ( l , r ) = ∑ i = l r a [ i ] g(l,r)=\sum_{i=l}^r a[i] g(l,r)=i=lra[i]。这个式子应该是随便算的吧?
    对每个数字算贡献,数字 x x x包含它的区间有 c n t = i × ( n − i + 1 ) cnt=i\times (n-i+1) cnt=i×(ni+1)个,贡献就是: x × c n t x\times cnt x×cnt
  • 解析:
    还是算单个数字的贡献。
    考虑如果有一个数字 y y y,它比 x x x小。那么只要 x , y x,y x,y在一个区间内,这个 y y y的存在肯定会让值 x x x的贡献增加一次。
    那么这个 y y y使得 x x x增加的总贡献是多少次呢?
    答案是:若 y y y x x x前面: p l a c e [ y ] × ( n − p l a c e [ x ] + 1 ) place[y]\times (n-place[x]+1) place[y]×(nplace[x]+1);若 y y y x x x后面: p l a c e [ x ] × ( n − p l a c e [ y ] + 1 ) place[x]\times (n-place[y]+1) place[x]×(nplace[y]+1)
    既然这样,我就从前往后和从后往前算两次算贡献即可。
    很明显这个东西用一个树状数组维护就可以了。相当于权值线段树吧?就是每个点代表的是权值,维护的是他的下标值,就是他的位置。
    看代码就懂了。
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define eb emplace_back
#define o2(x) (x)*(x)
#define all(x) (x).begin(), (x).end()
#define BASE_MAX 62
#define debug(x) cout << "[" << x << "]\n"
#define endl "\n"
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
inline LL read(){
  LL x=0;int f=0;char ch=getchar();
  while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
  while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
  return x=f?-x:x;
}
inline void write(LL x) {
    if(x==0){putchar('0'),putchar('\n');return;}
    if(x < 0) {putchar('-');x=-x;}
    static char s[23];int l = 0;
    while(x!=0)s[l++]=x%10+48,x/=10;
    while(l)putchar(s[--l]);
    putchar('\n');
}
int lowbit(int x) {return x&(-x);}
template<class T>T Max(T a1,T a2){ return a1>a2?a1:a2; }
template<class T>T Max(T a1,T a2,T a3){ return Max(a1,Max(a2,a3)); }
template<class T>T Max(T a1,T a2,T a3,T a4){ return Max(a1,a2,Max(a3,a4)); }
template<class T>T Min(T a1,T a2){ return a1<a2?a1:a2; }
template<class T>T Min(T a1,T a2,T a3){ return Min(a1,Min(a2,a3)); }
template<class T>T Min(T a1,T a2,T a3,T a4){ return Min(a1,a2,Min(a3,a4)); }

const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int HMOD[] = {1000000009, 1004535809};
const LL BASE[] = {1572872831, 1971536491};
const int mod = 1e9 + 7;
const int MXN = 1e6 + 7;

LL bit[MXN];
void bit_add(int x, int v, int N) {while(x <= N+1) bit[x] += v, x += lowbit(x);}
LL bit_sum(int x) {LL ans=0;for(;x;x-=lowbit(x))ans+=bit[x];return ans%mod;}
int n, m;
LL ar[MXN], ans;
int br[MXN];
std::vector<int> vs;
int get_id(int x) {return lower_bound(all(vs), x)-vs.begin()+1;}
int main() {
#ifndef ONLINE_JUDGE
    freopen("E://ADpan//in.in", "r", stdin);
    //freopen("E://ADpan//out.out", "w", stdout);
#endif
    n = read();
    for(int i = 1; i <= n; ++i) ar[i] = read(),vs.eb(ar[i]),ans=(ans+ar[i]*i%mod*(n-i+1)%mod)%mod;
    sort(all(vs));
    assert((int)vs.size() == n);
    for(int i = 1; i <= n; ++i) {
        br[i] = get_id(ar[i]);
        ans = (ans + bit_sum(br[i]-1)*(n-i+1)%mod*ar[i]%mod)%mod;
        bit_add(br[i], i, n);
    }
    for(int i = 0; i <= n+1; ++i) bit[i] = 0;
    for(int i = n; i >= 1; --i) {
        ans = (ans + bit_sum(br[i]-1)*i%mod*ar[i]%mod)%mod;
        bit_add(br[i], n-i+1, n);
    }
    write((ans%mod+mod)%mod);
    return 0;
}
Problem Description:

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值