hdu 6058 To my boyfriend (计算贡献,思维)

题意: 给你一个全排列,要你求这个序列的所有区间的第k大的和

思路:比赛的时候一看就知道肯定是算贡献,也知道是枚举每个数,然后看他在多少个区间是第K大,然后计算他的贡献就可以了,但是没有找到如何在o(k)的时间内找到这k个区间,然后就一直挂机,惨惨惨

感觉官方题解的思路就很棒啊:

我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x.=

我们考虑从小到大枚举x,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳k次,删除也是O(1)的。

时间复杂度:O(nk)

代码:

/** @xigua */
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <cstring>
#include <queue>
#include <set>
#include <string>
#include <map>
#include <climits>
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 5e5 + 5;
const int mod = 1e9 + 9;
const int mod2 = 1e9 + 7;
const int INF = 1e8 + 5;
const ll inf = 1e15 + 5;
const db eps = 1e-5;
const ll hp = 233333;
int a[maxn], pos[maxn], pre[maxn], nex[maxn];
ll pp[105], np[105];

void solve() {
    int n, k; cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
        pos[a[i]] = i;
        pre[i] = i - 1;
        nex[i] = i + 1;
    }
    pre[0] = -1, nex[n+1] = n + 2;
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        int t1 = 0, t2 = 0;
        int curp = pos[i];
        for (int j = curp; j >= 0 && t1 <= k; j = pre[j]) {
            pp[++t1] = j;
        }
        for (int j = curp; j <= n + 1 && t2 <= k; j = nex[j]) {
            np[++t2] = j;
        }
        for (int j = 1; j <= t1 - 1; j++) {
            if (k - j + 2 > t2) continue;
            ll tmp = (pp[j] - pp[j+1]) * (np[k - j + 2] - np[k - j + 1]);
            ans += tmp * i;
        }
        //删除当前节点 相当于链表
        int tp = pre[curp], tn = nex[curp];
        nex[tp] = tn, pre[tn] = tp;
    }
    cout << ans << endl;
}

int main() {
    int t = 1, cas = 1;
   // freopen("in.txt", "r", stdin);
   // freopen("out.txt", "w", stdout);
   // init();
    scanf("%d", &t);
    while(t--) {
       // printf("Case %d: ", cas++);
        solve();
    }
    return 0;
}

  

时间: 2024-10-12 20:15:30

hdu 6058 To my boyfriend (计算贡献,思维)的相关文章

【链表】2017多校训练3 HDU 6058 Kanade&#39;s sum

acm.hdu.edu.cn/showproblem.php?pid=6058 [题意] 给定一个排列,计算 [思路] 计算排列A中每个数的贡献,即对于每个ai,计算有ni个区间满足ai是区间中的第k大,那么ai对答案的贡献就是ai*ni 以ai为起点,统计ai右边离ai最近的,比ai大的k个数的位置 同理统计左边的位置,组合得到答案 关键是得到比ai大的离ai最近的k个数的位置 因为是排列,所以每个数都不相等,可以记录每个数的位置,然后从小到大枚举ai,这样维护一个双向链表,保证链表中的数就是

HDU 6058 Kanade&#39;s sum(链表)

http://acm.hdu.edu.cn/showproblem.php?pid=6058 题意:找出所有区间第K大的值之和. 思路: 又有点贡献值的味道,就是考虑当前这个数贡献了几个区间. 然后往左和往右分别找大于当前数的k-1个数,这样就可以确定区间的个数,这要求我们从小到大找 并且找完之后需要删除这个数,用链表来维护. 删除元素的目的是为了加速,保证了当前查找的元素是最小值,所以只需要跳跃寻找k次就可以.具体看代码. 1 #include<iostream> 2 #include<

hdu 6058 Kanade&#39;s sum(链表)

题目链接:hdu 6058 Kanade's sum 题意: 给你一个n个数的排列,问你全部区间第k大的总和为多少. 题解: 我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x. 我们考虑从小到大枚举xxx,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳kkk次,删除也是O(1)的. 时间复杂度:O(nk) 这题只要是知道能从小到大枚举就好办了. 1 #include<bits/stdc++.h> 2 #defi

HDU 6058 Kanade&#39;s sum —— 2017 Multi-University Training 3

Kanade's sum Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2512    Accepted Submission(s): 1045 Problem Description Give you an array A[1..n]of length n. Let f(l,r,k) be the k-th largest eleme

hdu 4923 Room and Moor (单调栈+思维)

题意: 给一个0和1组成的序列a,要构造一个同样长度的序列b.b要满足非严格单调,且 值为0到1的实数.最后使得  sum((ai-bi)^2)最小. 算法: 首先a序列开始的连续0和末尾的连续1是可以不考虑的.因为只要b序列对应开头为0. 末尾为1,既不影响单调性又能使对应的(ai-bi)^2=0. 然后, 先找111100.11100.10这样以1开始以0结束的序列块.每一块对应的b值相等且均为 这一块的平均值,即1的个数/0和1的总个数. 但是要满足b的单调性,则我们用栈来维护,如果后面一

hdu 6058 思维

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6058 分析题目的时候,由于枚举的区间很多,而第k大的值范围小,应该要想到去枚举第k大的值然后找到这个值对答案的贡献. 题解:我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的kk大值是xx.(这个地方自己举几个例子就知道了) 我们考虑从小到大枚举x,每次维护一个链表(我写了一个双链表),链表里只有大于x的数,每次求x对答案的贡献的时候,直接在链表中x的位置

HDU 4370 0 or 1(spfa+思维建图+计算最小环)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4370 题目大意:有一个n*n的矩阵Cij(1<=i,j<=n),要找到矩阵Xij(i<=1,j<=n)满足以下条件: 1.X 12+X 13+...X 1n=1  2.X 1n+X 2n+...X n-1n=1  3.for each i (1<i<n), satisfies ∑X ki (1<=k<=n)=∑X ij (1<=j<=n). 举个例子

hdu 6052 - To my boyfriend

题目 OvO click here http://acm.hdu.edu.cn/showproblem.php?pid=6052 解 分开考虑每种颜色 pre[i][j]代表第j列最近一个i颜色的行数,ppre是次近 calcu(li,ji,x,y,clr)表示从col=li到col=ri,计算(x,y)点对mp[x][y]=clr颜色有贡献的矩形的个数(其实并不是,准确说是(n-i+1)*(calcu(1,m,i,j,mp[i][j])-calcu(1,j-1,i,j,mp[i][j])-ca

hdu 6058

http://acm.hdu.edu.cn/showproblem.php?pid=6058 题意:求区间第K大然后乘以它本身的总和 思路:枚举X,维护一个链表,这个链表是记录比它小的一些,比他大的有多少个的一个链表 因为在这个链表中隔K个的值,然后取第K大就一定是X 然后维护这个链表呢,就是指已经枚举过的X就不要出现在这个链表里面了,因为如果它的值比这个X要小的话,肯定是不会影响这个第K大的 然后不可能出现比它大的情况,因为我们枚举X是从小到大枚举的,所以这个问题就可以化解 1 #includ