hdu多校第五场1004 (hdu6627) equation 1 计算几何

题意:

给你一个C,再给你n组a,b,让你求x取什么值的时候,$ \sum_{i=1}^n |a_i*x+b_i| =C $,要求求出解的个数,并用最简分数从小到大表示,如果有无穷多解,输出-1.

题解:

其实这些方程就是在平面上的一组曲线,都是V形的,最低点都在x轴上,求出所有的零点,以这个零点从左到右排序。

容易看出,这些函数之和也是一条曲线y=f(i),这条曲线最多有n个转折点,那么就在这n个转折点分出的n+1个区间内,和n个点上,用比例公式找和y=C的交点即可。无穷多解的情况是存在一条与y=C重合的线段。

首先预处理出f(i)上所有转折点的值,注意n的范围是1e5,因此不可能让你$O(n^2)$求每一点的值,其实,只需维护a与b的前缀和和后缀和,要求某点$x_k$时,将零点在此点左边的函数取正,零点在此点右边的的函数取反。

$(\sum_{i=1}^{k-1}a_i) *x_k+\sum_{i=1}^{k-1}b_i-(\sum_{i=k+1}^{n}a_i) *x_k-\sum_{i=k+1}^{n}b_i$

注意判断零点重合情况。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<stack>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef long long ll;
const int M = 1e5 + 10;
const double eps = 1e-7;
const LL mod = 998244353;
const LL lINF = 0x3f3f3f3f3f3f3f3f;
struct node {
    int a, b;
}tr[M];
int t;
int n, c;
int fenzi[M], fenmu[M];
int ans;
int gcd(int a, int b)
{
    if (!b)
        return a;
    else
        return gcd(b, a % b);
}
double lst;
bool cmp(node x, node y)
{
    return x.a * y.b - x.b * y.a < 0;
}
bool cmp2(node x, node y)
{
    return (double)x.b / -x.a < (double)y.b / -y.a;
}
bool cmp1(node x, node y)
{
    return (double)x.b / -x.a <= (double)y.b / -y.a;
}
int suma[M], sumb[M];
int flag;
double nw;
double nx;
int main()
{
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &c);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d%d", &tr[i].a, &tr[i].b);
        }
        sort(tr + 1, tr + n + 1, cmp);
        suma[0] = sumb[0] = 0;
        for (int i = 1; i <= n; i++)
        {
            suma[i] = suma[i - 1] + tr[i].a;
            sumb[i] = sumb[i - 1] + tr[i].b;
        }
        flag = ans = 0;
        lst = -10000.0;
        for (int i = 0; i <= n; i++)
        {
            int tmpa = -suma[n];
            int tmpb = -sumb[n];
            tmpa += 2 * suma[i];
            tmpb += 2 * sumb[i];
            nw = (double)sumb[i] / suma[i];
            nx = (double)sumb[i + 1] / suma[i + 1];
            if (fabs(nw - nx) < eps)
                continue;
            if (!tmpa && tmpb == c)
            {
                flag = 1;
                break;
            }
            if (!i)
            {
                node tmpc;
                tmpc.a = tmpa, tmpc.b = tmpb - c;
                if (cmp1(tmpc, tr[1]))
                {
                    fenzi[ans] = -tmpc.b;
                    fenmu[ans] = tmpa;
                    int d = gcd(fenzi[ans], fenmu[ans]);
                    fenzi[ans] /= d;
                    fenmu[ans] /= d;
                    if (fenmu[ans] < 0)
                    {
                        fenzi[ans] = -fenzi[ans], fenmu[ans] = -fenmu[ans];
                    }
                    ans++;
                }
            }
            else if (i == n)
            {
                node tmpc;
                tmpc.a = tmpa, tmpc.b = tmpb - c;
                if (cmp2(tr[n], tmpc))
                {
                    fenzi[ans] = -tmpc.b;
                    fenmu[ans] = tmpa;
                    int d = gcd(fenzi[ans], fenmu[ans]);
                    fenzi[ans] /= d;
                    fenmu[ans] /= d;
                    if (fenmu[ans] < 0)
                    {
                        fenzi[ans] = -fenzi[ans], fenmu[ans] = -fenmu[ans];
                    }
                    ans++;
                }
            }
            else
            {
                node tmpc;
                tmpc.a = tmpa, tmpc.b = tmpb - c;
                if (cmp2(tr[i], tmpc) && cmp1(tmpc, tr[i + 1]))
                {
                    fenzi[ans] = -tmpc.b;
                    fenmu[ans] = tmpa;
                    int d = gcd(fenzi[ans], fenmu[ans]);
                    fenzi[ans] /= d;
                    fenmu[ans] /= d;
                    if (fenmu[ans] < 0)
                    {
                        fenzi[ans] = -fenzi[ans], fenmu[ans] = -fenmu[ans];
                    }
                    ans++;
                }
            }
            lst = (double)(tmpb - c) / tmpa;
        }
        if (flag)
        {
            printf("-1\n");
        }
        else
        {
            printf("%d", ans);
            for (int i = 0; i < ans; i++)
            {
                printf(" %d/%d", fenzi[i], fenmu[i]);
            }
            puts("");
        }
    }
}

原文地址:https://www.cnblogs.com/isakovsky/p/11309173.html

时间: 2024-08-01 20:50:30

hdu多校第五场1004 (hdu6627) equation 1 计算几何的相关文章

2014 HDU多校弟五场J题 【矩阵乘积】

题意很简单,就是两个大矩阵相乘,然后求乘积. 用 Strassen算法 的话,当N的规模达到100左右就会StackOverFlow了 况且输入的数据范围可达到800,如果变量还不用全局变量的话连内存开辟都开不出来 1 #pragma comment(linker, "/STACK:16777216") 2 #include <iostream> 3 #include <stdio.h> 4 #define ll long long 5 using namesp

2014 HDU多校弟五场A题 【归并排序求逆序对】

这题是2Y,第一次WA贡献给了没有long long 的答案QAQ 题意不难理解,解题方法不难. 先用归并排序求出原串中逆序对的个数然后拿来减去k即可,如果答案小于0,则取0 学习了归并排序求逆序对的方法,可以拿来当模板 TVT 贴代码了: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream&g

hdu 6088 Rikka with Rock-paper-scissors (2017 多校第五场 1004) 【组合数学 + 数论 + 模意义下的FFT】

题目链接 首先利用组合数学知识,枚举两人的总胜场数容易得到 这还不是卷积的形式,直接搞的话复杂度大概是O(n^2)的,肯定会TLE.但似乎和卷积有点像?想半天没想出来..多谢Q巨提醒,才知道可以用下面这个公式进行转化 最后,化得的公式为 另外注意,上式右边是一个卷积的形式,但是,所得和的第一项是不需要加上的(不过图中公式没有体现).结合实际意义大概就是,i==0&&j==0时,gcd(i,j)不存在约数d,虽然0可以被任意正整数整除 & 第一项不为0 #include<bit

hdu多校第五场1007 (hdu6630) permutation 2 dp

题意: 给你n个数,求如下限制条件下的排列数:1,第一位必须是x,2,最后一位必须是y,3,相邻两位之差小于等于2 题解: 如果x<y,那么考虑把整个数列翻转过来,减少讨论分支. 设dp[n]为限制1和n在两边,相邻的数之差小于等于2的排列方案. dp[0]=1 dp[1]=1 dp[2]=2 dp[3]=3 如果x==1 y==n 直接用公式dp[i]=dp[i-1]+dp[i-3]求解,将i代入为n-1-1. 如果x!=1 或者y!=n,假如对于12个的情况,x=4,y=9 那么,1,2,3

2014多校第十场1004 || HDU 4974 A simple water problem

题目链接 题意 : n支队伍,每场两个队伍表演,有可能两个队伍都得一分,也可能其中一个队伍一分,也可能都是0分,每个队伍将参加的场次得到的分数加起来,给你每个队伍最终得分,让你计算至少表演了几场. 思路 : ans = max(maxx,(sum+1)/2) :其实想想就可以,如果所有得分中最大值没有和的一半大,那就是队伍中一半一半对打,否则的话最大的那个就都包了. 1 #include <cstdio> 2 #include <cstring> 3 #include <st

2014多校第五场1010 || HDU 4920 Matrix multiplication(矩阵乘法优化)

题目链接 题意 : 给你两个n*n的矩阵,然后两个相乘得出结果是多少. 思路 :一开始因为知道会超时所以没敢用最普通的方法做,所以一直在想要怎么处理,没想到鹏哥告诉我们后台数据是随机跑的,所以极端数据是不可能会有的,而我们一开始一直在想极端数据能接受的方法......后来看了鹏哥的做法,就是把是0的地方都跳过就可以了,用矩阵保存前一个非0数的位置是多少.二师兄给我看了一个代码,人家根本没用别的优化,直接将最里层k的循环提到了最外层,然后就AC了,对此我表示无语. 1 #include <cstd

2014多校第五场1001 || HDU 4911 Inversion (归并求逆序数)

题目链接 题意 : 给你一个数列,可以随意交换两相邻元素,交换次数不超过k次,让你找出i < j 且ai > aj的(i,j)的对数最小是多少对. 思路 : 一开始想的很多,各种都想了,后来终于想出来这根本就是求逆序数嘛,可以用归并排序,也可以用树状数组,不过我们用树状数组做错了,也不知道为什么.求出逆序数来再减掉k次,就可以求出最终结果来了.求逆序数链接1,链接2 1 #include <stdio.h> 2 3 int left[250003], right[250003];

多校第五场 归并排序

HDU 4911 Inversion 考点:归并排序 思路:这题呀比赛的时候忘了知道可以用归并排序算出逆序数,但是忘了归并排序的实质了,然后不会做-- 因为看到题上说是相邻的两个数才能交换的时候,感觉归并排序好像不是得要相邻的呀,然后就这样晕--刚才重新看了才发现,归并就是相邻的交换的,正好是用来求逆序数的,唉--真的是做这个归并排序比赛就来了--真好! #include<iostream> #include<cstdio> #include<cstring> #inc

2014 HDU多校弟八场H题 【找规律把】

看了解题报告,发现看不懂 QAQ 比较简单的解释是这样的: 可以先暴力下达标,然后会发现当前数 和 上一个数 的差值是一个 固定值, 而且等于当前数与i(第i个数)的商, 于是没有规律的部分暴力解决,有规律的套公式 //#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h> #include <iostream> #include <cstring&g