zoukankan      html  css  js  c++  java
  • [HNOI2016]序列

    传送门


    这题挺有意思,像数据结构,结果完全用不上。


    切入点挺怪的,我也不知道为什么能这么想:先求出所有前缀的答案。

    (f[i])表示右端点在(i),左端点在([1,i])的所有区间的最小值之和。

    (pre_i)表示在(i)之前第一个比(a_i)小的数的位置,那么左端点在([pre_i + 1,i])之间的区间的最小值全是(a_i),即贡献了(a_i * (i - pre_i))

    那左端点在([1,pre_i])的这些区间呢?接下来是关键:([j, i](1 leqslant j leqslant pre_i))的这些区间的最小值,和([j, pre_i](1 leqslant j leqslant pre_i))的最小值相同,也就是说,贡献是一样的!

    那么就有:(f[i] = f[pre_i]+a_i * (i - pre_i)).

    而且,(f[i] - f[pre_i])就是([j, i](pre_i < j leqslant i))的这些区间的最小值之和。

    至于求(pre_i),用单调栈即可。


    求完上述的递推式后,这道题就好做了。

    对于任意的区间([L, R]),求出区间最小值的位置(p),那么所有区间跨过(p)的区间的贡献就是(a[p] * (R - p + 1) * (p - L + 1)).

    而对于没有跨过(p)的区间,考虑右侧的区间,那不正好就是上面的(f[i] - f[p])嘛!

    对于左侧的那些区间,我们对称的处理出(f'),那么左侧区间的贡献就是(f'[L] - f'[p])了。

    所以每一个询问是(O(1))的,总复杂度(O(nlogn)),瓶颈在于RMQ的预处理。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<queue>
    #include<assert.h>
    #include<ctime>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    const int N = 17;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    In void MYFILE()
    {
    #ifndef mrclr
    	freopen(".in", "r", stdin);
    	freopen(".out", "w", stdout);
    #endif
    }
    
    int n, Q, a[maxn];
    
    ll f1[maxn], sum1[maxn], f2[maxn], sum2[maxn];
    int st[maxn], top = 0, pre[maxn];
    In void solve(ll *f, ll *sum)
    {
    	top = 0;
    	for(int i = n; i; --i)
    	{
    		while(top && a[i] <= a[st[top]]) pre[st[top--]] = i;
    		st[++top] = i;
    	}
    	while(top) pre[st[top--]] = 0;
    	for(int i = 1; i <= n; ++i) f[i] = f[pre[i]] + 1LL * a[i] * (i - pre[i]);
    	for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + f[i];
    }
    
    int dp[maxn][N + 2], ha[maxn];
    In void rmq_init()
    {
    	for(int i = 1; i <= n; ++i) dp[i][0] = i;
    	for(int j = 1; (1 << j) <= n; ++j)
    		for(int i = 1; i + (1 << j) - 1 <= n; ++i)
    		{
    			int tp1 = dp[i][j - 1], tp2 = dp[i + (1 << (j - 1))][j - 1];
    			dp[i][j] = a[tp1] < a[tp2] ? tp1 : tp2;
    		}
    	for(int i = 2; i <= n; ++i) ha[i] = ha[i >> 1] + 1;
    }
    In int query(int L, int R)
    {
    	int k = ha[R - L + 1];
    	int tp1 = dp[L][k], tp2 = dp[R - (1 << k) + 1][k];
    	return a[tp1] < a[tp2] ? tp1 : tp2;
    }
    
    int main()
    {
    	n = read(), Q = read();
    	for(int i = 1; i <= n; ++i) a[i] = read();
    	solve(f1, sum1);
    	reverse(a + 1, a + n + 1);
    	solve(f2, sum2);
    	reverse(a + 1, a + n + 1);
    	reverse(f2 + 1, f2 + n + 1);
    	reverse(sum2 + 1, sum2 + n + 1);
    	rmq_init();
    	for(int i = 1; i <= Q; ++i)
    	{
    		int L = read(), R = read();
    		int p = query(L, R);
    		ll ans1 = sum1[R] - sum1[p] - f1[p] * (R - p);
    		ll ans2 = sum2[L] - sum2[p] - f2[p] * (p - L);
    		write(1LL * a[p] * (R - p + 1) * (p - L + 1) + ans1 + ans2), enter;
    	}
    	return 0;
    }
    
  • 相关阅读:
    HTML5结构
    HTML5新增的非主体元素header元素、footer元素、hgroup元素、adress元素
    CF GYM 100703G Game of numbers
    CF GYM 100703I Endeavor for perfection
    CF GYM 100703K Word order
    CF GYM 100703L Many questions
    CF GYM 100703M It's complicate
    HDU 5313 Bipartite Graph
    CF 560e Gerald and Giant Chess
    POJ 2479 Maximum sum
  • 原文地址:https://www.cnblogs.com/mrclr/p/15083783.html
Copyright © 2011-2022 走看看