Cycle Function - 题解【二分】

题面

这是2019四川省赛的C题。这里放上CodeForces的链接:C. Cycle Function - Codeforces

Fish is learning functions! He has a linear function f(x)=Ax+B and N numbers x1,x2,,xN. Now he is curious about for each function g(x) in

{g1(x)=c1x+d1g2(x)=c2x+d2gM(x)=cMx+dM}

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 x1,x2,,xN 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 x1,x2,,xN.

Then M lines follow, each line containing two real numbers ci,di indicating a function gi(x)=cix+di mentioned above.

All numbers in the same line are separated by one space.

Output
For each test case, you should output Case 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 gi(x).

Your answers will be considered correct if its absolute error does not exceed 106.

Limits

time limit per test: 5 seconds
memory limit per test: 256 megabytes
input: standard input
output: standard output

Note

1T100
1N,M105
100A,B,xi,ci,di100
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.0

Example Output

Case 1:
7.800000
28.200000
Case 2:
12.600000
36.900000

大意

给定一个线性函数f(x)=Ax+B和一个线性函数组gi(x)=cix+di,定义函数D(x)=|f(g(x))x|+|g(f(x))x|,对于给定的一组数xi,i=i,2,,n,求关于线性函数组里的每个函数,i=1nD(xi)的值。

题解

我们对这两个绝对值符号里面的内容做一下数学变换,记Ac1=a,Ad+B=p,Bc+d=q

f(g(x))x=A(cx+d)+B=Acx+Ad+Bx=(Ac1)x+(Ad+B)=ax+p

g(f(x))x=c(Ax+B)+d=Acx+Bc+dx=(Ac1)x+(Bc+d)=ax+q

式子变得简单了不少。但是绝对值仍然是一个让人非常讨厌的东西,需要对正数与负数进行分类讨论。而且,本题有至多1e5个变量和 1e5个函数,虽然时间限制是5秒,但是平方复杂度的暴力解法必定会超时。我们考虑到,对于线性函数F(x)=kx+b,当k=0时值永远为b,否则其零点为x0=bk,因此我们只需要特判系数a是否为0,然后考虑大于x0的数以及不大于x0的数,分别计算即可,一连串数据的求和可以使用前缀和来维护,分界点排序后使用二分查找函数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;
}

/*
          _           _    _            _
    /\   | |         | |  | |          (_)
   /  \  | | _____  _| |__| | ___  _ __ _ _ __   __ _
  / /\ \ | |/ _ \ \/ /  __  |/ _ \| '__| | '_ \ / _` |
 / ____ \| |  __/>  <| |  | | (_) | |  | | | | | (_| |
/_/    \_\_|\___/_/\_\_|  |_|\___/|_|  |_|_| |_|\__, |
                                                 __/ |
                                                |___/
*/
posted @   AlexHoring  阅读(93)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示