【map离散&容斥】Ghosts @Codeforces Round #478 (Div. 2) D

传送门
题意:给你一条直线的斜率a和截距b,和某一时刻n个在直线上的点的横坐标,以及沿坐标轴方向的速度。问你这些点在(-∞,+∞)的时间内的碰撞次数。

solution
设两个点在t时刻相碰,有:

x1+vx1t=x2+vx2tx1+vx1t=x2+vx2t
y1+vy1t=y2+vy2ty1+vy1t=y2+vy2t


消去t,可以得到

x1x2vx2vx1=y1y2vy2vy1x1−x2vx2−vx1=y1−y2vy2−vy1


而在直线上有

y1y2=a(x1x2)y1−y2=a(x1−x2)


进一步整理可以得到

vy2avx2=vy1avx1vy2−avx2=vy1−avx1


也就是说 当两个点的 vyavxvy−avx 值相等时,两个点就会相碰
开一个map记录每一个 vyavxvy−avx 值对应的点的数量
同时也要注意,如果两个点具有相同的vxvx vyvy ,它们的vyavxvy−avx 也是相同的,但此时两个点相对静止 不会相碰
所以每次统计答案时,除了加上与当前点vyavxvy−avx 相同的点的数量,还要减去与当前点相对静止的点的数量(可以另开一个map记录一下)

#define IN_LB() freopen("C:\Users\acm2018\Desktop\in.txt","r",stdin)
#define OUT_LB() freopen("C:\Users\acm2018\Desktop\out.txt","w",stdout)
#define IN_PC() freopen("C:\Users\hz\Desktop\in.txt","r",stdin)
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<ll,ll> pll;
map<ll,int> mp;
map<pll,int> same;

int main() {
//    IN_LB();
    ll n,a,b,ans=0;
    scanf("%lld%lld%lld",&n,&a,&b);
    for(int i=0; i<n; i++) {
        ll x,vx,vy;
        scanf("%lld%lld%lld",&x,&vx,&vy);
        ll res = vy-a*vx;
        pll node = {vx,vy};
        ans+=mp[res] - same[node];
        mp[res]++;
        same[node]++;
    }
    printf("%lld
",ans*2);
    return 0;
}
原文地址:https://www.cnblogs.com/NeilThang/p/9356611.html