这是2019四川省赛的C题。这里放上CodeForces的链接:C. Cycle Function - Codeforces
Fish is learning functions! He has a linear function \(f(x)=Ax+B\) and \(N\) numbers \(x_1,x_2,⋯,x_N\). Now he is curious about for each function \(g(x)\) in
\[ \left\{ \begin{matrix} g_1(x)=c_1x+d_1\\ g_2(x)=c_2x+d_2\\ \vdots\\ g_M(x)=c_Mx+d_M \end{matrix} \right\} \]how to calculate the difference between \(f(g(x))\) and \(g(f(x))\).
As smart as Fish is, he soon comes up with a function \(D(x)=|f(g(x))−x|+|g(f(x))−x|\) and uses the sum over \(x_1,x_2,⋯,x_N\) as the difference.
Can you tell him all the differences immediately?
Input
The first line of input contains an integer \(T\), representing the number of test cases.Then for each test case:
The first line contains two integers \(N, M\) as mentioned above and then two real numbers \(A, B\) indicating the given function \(f(x)=Ax+B\).
The second line contains \(N\) real numbers \(x_1,x_2,⋯,x_N\).
Then \(M\) lines follow, each line containing two real numbers \(c_i, d_i\) indicating a function \(g_i(x)=c_ix+d_i\) mentioned above.
All numbers in the same line are separated by one space.
Output
For each test case, you should outputCase x:
in the first line, where \(x\) indicates the case number starting from \(1\).Then \(M\) lines follow, the \(i\)-th line of which contains a real number representing the difference for given function \(g_i(x)\).
Your answers will be considered correct if its absolute error does not exceed \(10^{−6}\).
Limits
time limit per test: 5 seconds
memory limit per test: 256 megabytes
input: standard input
output: standard outputNote
\(1≤T≤100\)
\(1≤N,M≤10^5\)
\(−100≤A,B,x_i,c_i,d_i≤100\)
For \(90\%\) test cases: \(max(N,M)≤1000\)Example Input
2 3 2 2.0 3.0 1.0 2.0 3.0 0.4 -2.0 0.6 -5.0 3 2 2.5 2.0 1.0 2.0 3.0 0.4 -2.0 0.6 -5.0Example Output
Case 1: 7.800000 28.200000 Case 2: 12.600000 36.900000
给定一个线性函数\(f(x)=Ax+B\)和一个线性函数组\(g_i(x)=c_ix+d_i\),定义函数\(D(x)=|f(g(x))−x|+|g(f(x))−x|\),对于给定的一组数\(x_i,\enspace i=i,2,\dots,n\),求关于线性函数组里的每个函数,$ \sum_{i=1}^{n} D(x_i)$的值。
我们对这两个绝对值符号里面的内容做一下数学变换,记\(Ac-1=a,Ad+B=p,Bc+d=q\):
\[f(g(x))-x=A(cx+d)+B=Acx+Ad+B-x=(Ac-1)x+(Ad+B)=ax+p \]\[g(f(x))-x=c(Ax+B)+d=Acx+Bc+d-x=(Ac-1)x+(Bc+d)=ax+q \]式子变得简单了不少。但是绝对值仍然是一个让人非常讨厌的东西,需要对正数与负数进行分类讨论。而且,本题有至多1e5个变量和 1e5个函数,虽然时间限制是5秒,但是平方复杂度的暴力解法必定会超时。我们考虑到,对于线性函数\(F(x)=kx+b\),当\(k=0\)时值永远为\(b\),否则其零点为\(x_0=-\frac{b}{k}\),因此我们只需要特判系数\(a\)是否为0,然后考虑大于\(x_0\)的数以及不大于\(x_0\)的数,分别计算即可,一连串数据的求和可以使用前缀和来维护,分界点排序后使用二分查找函数lower_bound即可。这题知道思路了就很简单,但是确实蛮难想的……
排序复杂度为\(O(NlogN)\),对每个函数二分查找总复杂度为\(O(MlogN)\),综合复杂度为\(O((M+N)logN)\),可以接受。
另:本题卡输入输出,要使用C风格的输入输出或者手搓快读快写。Java或者Python选手还是放弃吧o( ̄▽ ̄)ブ笔者使用关闭流同步的cin\cout超时,改scanf\printf只用了2000ms……
下面是代码:
#include <bits/stdc++.h> #define GRP int T;cin>>T;rep(C,1,T) #define FAST ios::sync_with_stdio(false);cin.tie(0); #define rep(i,a,b) for(int i=a;i<=b;++i) #define rrep(i,a,b) for(int i=a;i>=b;--i) #define elif else if #define mem(arr,val) memset(arr,val,sizeof(arr)) typedef long long ll; typedef unsigned long long ull; using namespace std; const double EPS = 1e-8; int n, m; double a, b; double xs[100010], x[100010], c, d; double ans; int main() { xs[0] = 0; GRP { scanf("%d %d %lf %lf", &n, &m, &a, &b); printf("Case %d:\n", C); //读入并排序,求前缀和 rep(i, 1, n) { scanf("%lf", x + i); } sort(x + 1, x + 1 + n); rep(i, 1, n) { xs[i] = xs[i - 1] + x[i]; } //处理每个g(x) rep(i, 1, m) { scanf("%lf %lf", &c, &d); ans = 0; double a1 = a * c - 1, p = a * d + b, q = b * c + d; //计算系数 if (abs(a1) < EPS) { //浮点数为0应判断其绝对值小于一个极小值 ans = (abs(p) + abs(q)) * n; } else { //寻找分界点 int i1 = lower_bound(x + 1, x + 1 + n, -p / a1) - x - 1; int i2 = lower_bound(x + 1, x + 1 + n, -q / a1) - x - 1; //分别求值并且累加 ans += abs(a1 * (xs[i1] - xs[0]) + p * (i1)); ans += abs(a1 * (xs[n] - xs[i1]) + p * (n - i1)); ans += abs(a1 * (xs[i2] - xs[0]) + q * (i2)); ans += abs(a1 * (xs[n] - xs[i2]) + q * (n - i2)); } printf("%.7lf\n", ans); } } return 0; } /* _ _ _ _ /\ | | | | | | (_) / \ | | _____ _| |__| | ___ _ __ _ _ __ __ _ / /\ \ | |/ _ \ \/ / __ |/ _ \| '__| | '_ \ / _` | / ____ \| | __/> <| | | | (_) | | | | | | | (_| | /_/ \_\_|\___/_/\_\_| |_|\___/|_| |_|_| |_|\__, | __/ | |___/ */