每日一题7.26
P10455 Genius Acm - 洛谷
Advanced CPU Manufacturer (ACM) is one of the best CPU manufacturers in the world. 每天,该公司生产 n 台 CPU 并销售到世界各地。
ACM 公司的质检部门会对生产出的 CPU 进行成组测试,对一组(若干个)CPU 进行测试的方法如下:
-
随机从该组 CPU 中选取 m 对(即 2m 台),若总数不足 2m 台,则选取尽量多对。
-
对于每一对 CPU,测量它们之间的 Relative Performance Difference (RPD),并把第 i 对的 RPD 记为 Di。RPD 的计算方法在后面给出。
-
该组 CPU 的 Sqared Performance Difference (SPD) 由以下公式给出:
SPD=∑iDi2
- 该组 CPU 通过质检,当且仅当 SPD≤k, 其中 k 是给定常数。
ACM 公司生产的 CPU 性能很好,而质检部门制定的标准更是过于严格。通常他们把 n 台 CPU 作为一整组进行测试,这导致一些性能良好的 CPU 无法通过测试,生产部门对此颇有微词。作为质检部门的领导,小 S 在不更改质检测试流程的前提下,想出了这样一个主意:如果能够把 n 台 CPU 恰当地分成连续的若干段,使得每段 CPU 都能够通过成组测试,就可以解决当下的问题。
现在,小 S 已经知道了 n 台各自的性能表现 P1,⋯,Pn,两台 CPU 的 RPD 被定义为它们性能表现的差的绝对值。请你帮忙计算一下,至少把这些 CPU 分成多少段,才能使得每一段都能通过成组测试。
输入格式
每个测试点包含多组数据,第一行整数 T 给出数据组数。
对于每组数据,第一行三个整数 n,m,k,第二行 n 个整数 P1,⋯,Pn。
输出格式
对于每组数据,输出一个整表示答案。
输入输出样例
输入 #1复制
2 5 1 49 8 2 1 7 9 5 1 64 8 2 1 7 9
输出 #1复制
2 1
说明/提示
对于 20% 的数据,1≤n≤102 。
对于 40% 的数据, 1≤n≤103 。
对于另外 10% 的数据,k=0 。
对于另外 10% 的数据,0≤k≤1 。
对于另外 10% 的数据, m=1 。
对于另外 10% 的数据,1≤m≤2 。
对于 90% 的数据,0≤k≤1012 。
对于 100% 的数据,T≤12,1≤n,m≤5⋅105,0≤k≤1018,0≤Pi≤220 。
一个倍增的题。问至少分成多少段。
第一想法是一个一个插入,边插入边检查,这样的话就是n方的复杂度很明显超时了。
然后看了题解可以倍增然后归并一下,这样就是nlogn的复杂度
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, m, k;
vector<int> a(500005, 0),m1(500005, 0),m2(500005, 0);
bool check(int st, int ed, int eadd)
{int ans = 0;for (int i = ed; i < eadd; i++)m1[i] = a[i];sort(m1.begin() + ed, m1.begin() +eadd);排序[ed,eadd)int ll=st,lr=ed-1,rl=ed,rr=eadd-1,idx=0;while (ll <= lr && rl <= rr)//归并[st,ed)和[ed,eadd),因为前者已经有序。后者也已经排序{if(m1[ll] <= m1[rl])m2[idx++]=m1[ll++];elsem2[idx++]=m1[rl++];}while (ll <= lr)m2[idx++] = m1[ll++];while (rl <= rr)m2[idx++] = m1[rl++];for (int i = 0; i < m && i < idx; i++, idx--)ans += pow((m2[idx-1]-m2[i]), 2); //贪心求 SPD,检查是否符合条件return ans <= k;
}void solve()
{int res = 0;cin >> n >> m >> k;for (int i = 0; i < n; i++)cin >> a[i];int st = 0, ed = 0;//每一个小段的起点和终点【)while (ed < n){int add = 1;while (add > 0){if (ed+add <= n && check(st, ed, ed + add))//检查[st,ed+add)符不符合条件{ed+=add;//扩展edif(ed>=n)break;add <<= 1;//ad×2for(int i=st;i<ed+add;i++)m1[i]=m2[i-st];//合并归并后的[st,ed);}elseadd>>=1;//不符合条件,add➗2}st = ed;res++;}cout << res << endl;
}
signed main()
{ios::sync_with_stdio(false);cin.tie(0);int t = 1;cin >> t;while (t--){solve();}
}