【CodeForces】868F. Yet Another Minimization Problem

原题链接

题目大意是有N个数,分成K段,每一段的花费是这个数里相同的数的数对个数,要求花费最小

如果只是区间里相同数对个数的话,莫队就够了

而这里是!边单调性优化边莫队(只是类似莫队)!而移动的次数和分治的复杂度是一样的!

这个时候就不能用单调栈+二分了,得用分治

分治的方法就是\(Solve(l,r,ql,qr)\)表示我想计算区间\([l,r]\)的答案,然后转移过来的区间在\([ql,qr]\)

暴力计算出\(f[mid]\)的值,找到最优转移点是\(k\),然后分成\(Solve(l,mid,ql,k)\)和\(Solve(mid +1,r,k,qr)\)做下去

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <bitset>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
template<class T>
void read(T &res) {
    res = 0;T f = 1;char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        res = res * 10 + c - '0';
        c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) out(x / 10);
    putchar('0' + x % 10);
}
int N,K,a[MAXN],cnt[MAXN];
int64 f[22][MAXN],w = 0;
int nw,p,q;
int64 work(int l,int r) {
    while(q < r) w += cnt[a[++q]]++;
    while(p > l) w += cnt[a[--p]]++;
    while(p < l) w -= --cnt[a[p++]];
    while(q > r) w -= --cnt[a[q--]];
    return w;
}
int64 Calc(int a,int b) {
    return f[nw - 1][a] + work(a + 1,b);
}
void Solve(int l,int r,int ql,int qr) {
    if(l > r) return;
    int mid = (l + r) >> 1,p = min(qr,mid - 1);
    int k;
    f[nw][mid] = Calc(ql,mid);k = ql;
    for(int i = ql + 1 ; i <= p ; ++i) {
        int64 x = Calc(i,mid);
        if(x <= f[nw][mid]) {
            f[nw][mid] = x;k = i;
        }
    }
    Solve(l,mid - 1,ql,k);
    Solve(mid + 1,r,k,qr);
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    read(N);read(K);
    for(int i = 1 ; i <= N ; ++i) {read(a[i]);f[1][i] = f[1][i - 1] + cnt[a[i]]++;}

    for(int i = 2 ; i <= K ; ++i) {
        memset(cnt,0,sizeof(cnt));
        p = 1;q = 0;w = 0;
        nw = i;
        Solve(0,N,0,N);
    }
    out(f[K][N]);enter;
}

原文地址:https://www.cnblogs.com/ivorysi/p/11140649.html

时间: 2024-08-03 04:14:28

【CodeForces】868F. Yet Another Minimization Problem的相关文章

【dfs】hdu 1016 Prime Ring Problem

[dfs]hdu 1016 Prime Ring Problem 题目链接 刚开始接触搜索,先来一道基本题目练练手. 注意对树的深度进行dfs dfs过程中注意回退!!! 素数提前打表判断快一些 参考代码 /*Author:Hacker_vision*/ #include<bits/stdc++.h> #define clr(k,v) memset(k,v,sizeof(k)) using namespace std; const int _max=1e3+10;//素数打表 int n,pr

【BZOJ2318】Spoj4060 game with probability Problem 概率

[BZOJ2318]Spoj4060 game with probability Problem Description Alice和Bob在玩一个游戏.有n个石子在这里,Alice和Bob轮流投掷硬币,如果正面朝上,则从n个石子中取出一个石子,否则不做任何事.取到最后一颗石子的人胜利.Alice在投掷硬币时有p的概率投掷出他想投的一面,同样,Bob有q的概率投掷出他相投的一面. 现在Alice先手投掷硬币,假设他们都想赢得游戏,问你Alice胜利的概率为多少. Input 第一行一个正整数t,

【CF459D】 Pashmak and Parmida&#39;s problem [树状数组]

CF459D Pashmak and Parmida's problem 给出长度为n的序列a. f(i,j,x)表示ai..aj中x的出现次数. 求有多少对i,j满足f(1,i,ai) > f(j,n,aj).(i<j) 害挺水 就是开始计数那用的玄学vector超时了... 用 map/离散化预处理出 f(1, i, a[i]) 和 f(j, n, a[j]) 类似求逆序对,树状数组.维护 #include<bits/stdc++.h> using namespace std;

【codeforces】【比赛题解】#854 CF Round #433 (Div.2)

cf一如既往挺丧 看丧题点我! [A]分数 Petya是数学迷,特别是有关于分数的数学.最近他学了所谓一个分数被叫做"真分数"当且仅当其分子小于分母,而一个分数被叫做"最简分数"当且仅当其分子分母互质.在闲暇时间,Petya在用计算器研究:如何把最简真分数转换为小数等问题.有一天他不小心把除号(÷)按成了加号(+),导致他得到了分子与分母的和.Petya想要得到他原来的分数,但他很快发现这不是唯一的.所以现在他想要知道最大的最简真分数使得其分子与分母的和为n. 输入

【CodeForces】835D Palindromic characteristics

[算法]区间DP [题解]涉及回文问题的区间DP都可以用类似的写法,就是h[i][j]表示i~j是否回文,然后就可以O(1)判断回文了. f[i][j]=k表示该字符串是k-th字符串,因为首先要求回文,既然回文那么左半边和右半边就肯定一样了. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=5010; int f[maxn][maxn]

【codeforces】【比赛题解】#849 CF Round #431 (Div.2)

cf的比赛越来越有难度了--至少我做起来是这样. 先看看题目吧:点我. 这次比赛是北京时间21:35开始的,算是比较良心. [A]奇数与结束 "奇数从哪里开始,又在哪里结束?梦想从何处起航,它们又是否会破灭呢?" 给定一个长度为n的序列.确定能不能将序列分成奇数个长度为奇数的非空字串,而且这其中每个子串以奇数开头,以奇数结尾.可以只分成一个(1也是奇数). 输入 第一行一个正整数n,表示序列长度. 第二行n个整数,表示序列中的元素. 输出 输出"Yes"或"

【CodeForces】841C. Leha and Function(Codeforces Round #429 (Div. 2))

[题意]定义函数F(n,k)为1~n的集合中选择k个数字,其中最小数字的期望. 给定两个数字集A,B,A中任意数字>=B中任意数字,要求重组A使得对于i=1~n,sigma(F(Ai,Bi))最大. [算法]数学结论+数学期望+排序 [题解]很无奈,这题放在div2 C,难以推导的期望公式,广为人知的结论,容易观察样例得出的做法,都体现了这道题的不合理性. F(n,k)=(n+1)/(k+1) 公式推导可能触及我的知识盲区了QAQ 得到公式后,显然要求k尽可能小,n尽可能大,经验告诉我们随着两数

【CodeForces】585 E. Present for Vitalik the Philatelist

[题目]E. Present for Vitalik the Philatelist [题意]给定n个数字,定义一种合法方案为选择一个数字Aa,选择另外一些数字Abi,满足?gcd(Aa,Abi)=1,且gcd(Ab1...Abx)≠1,求方案数取模1e9+7.2<=n<=5*10^5,2<=ai<=10^7. [算法]数论,计数问题 [题解]

【CodeForces】578 C. Weakness and Poorness

[题目]C. Weakness and Poorness [题意]给定含n个整数的序列ai,定义新序列为ai-x,要使新序列的最大子段和绝对值最小,求实数x.n<=2*10^5. [算法]二分||三分||计算几何(凸包) [题解]Editorial 令正数最大子段和为A,负数最大子段和为B,绝对值是max(A,B).当x从小到大变化时,A由大变小,B由小变大. 容易发现这是一个下凸函数,可以用三分法求解. 但是,这道题卡精度(-11会WA,-12会T),解决方法是根据复杂度把循环次数卡到极限而不