Codeforces 961 容斥叉积判共线 树状数组递增思想题

A

B

C

D

给你N个点 问你能不能有两条直线穿过这N个点

首先假设这N个点是可以被两条直线穿过的 所以两条直线就把这N个点划分成两个集合

我们取1 2 3三个点这样必定会有两个点在一个集合内 check一下 如果不满足输出NO

#include <bits/stdc++.h>
#define PI acos(-1.0)
#define mem(a,b) memset((a),b,sizeof(a))
#define TS printf("!!!\n")
#define pb push_back
#define inf 1e9
//std::ios::sync_with_stdio(false);
using namespace std;
//priority_queue<int,vector<int>,greater<int>> que; get min
const double eps = 1.0e-10;
const double EPS = 1.0e-4;
typedef pair<int, int> pairint;
typedef long long ll;
typedef unsigned long long ull;
//const int maxn = 3e5 + 10;
const int turn[4][2] = {{1, 0}, { -1, 0}, {0, 1}, {0, -1}};
//priority_queue<int, vector<int>, less<int>> que;
//next_permutation
int n;
struct Point
{
        ll x, y;
        Point operator - (const Point& p) const
        {
                return {x - p.x, y - p.y};
        }
} p[100005];
inline bool cross(Point a, Point b)
{
        return a.y * b.x == a.x * b.y;
}
inline bool collinear(int x, int y, int z)
{
        return cross(p[x] - p[y], p[x] - p[z]);
}
int check(int x, int y)
{
        vector<int> todo;
        for (int i = 1; i <= n; i++)
        {
                if (!collinear(x, y, i))
                {
                        todo.pb(i);
                }
        }
        if (todo.size() <= 2)
        {
                return 1;
        }
        int now1, now2;
        now1 = todo[0], now2 = todo[1];
        for (auto i : todo)
        {
                if (!collinear(now1, now2, i))
                {
                        return 0;
                }
        }
        return 1;
}
int main()
{
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
                scanf("%lld %lld", &p[i].x, &p[i].y);
        }
        if (n <= 4)
        {
                cout << "YES" << endl;
                return 0;
        }
        int flag = 0;
        flag |= check(1, 2);
        flag |= check(1, 3);
        flag |= check(2, 3);
        if (flag)
        {
                cout << "YES" << endl;
        }
        else
        {
                cout << "NO" << endl;
        }
        return 0;
}
View Code

E

给你N个系列的电视剧 第i个系列有ai集 问你a[i]>=j&&a[j]>=i 这样的对数有多少对

考察一个递增思想 我们i从1循环到N 删去树状数组里集数为i的 这样下一次求的时候数组里就都是满足条件的了(开始的时候因为条件ai>=1 所以update(i,1))

(ai=min(ai,n) ai大于N的时候直接可以赋成N)

#include <bits/stdc++.h>
#define PI acos(-1.0)
#define mem(a,b) memset((a),b,sizeof(a))
#define TS printf("!!!\n")
#define pb push_back
#define inf 1e9
//std::ios::sync_with_stdio(false);
using namespace std;
//priority_queue<int,vector<int>,greater<int>> que; get min
const double eps = 1.0e-10;
const double EPS = 1.0e-4;
typedef pair<int, int> pairint;
typedef long long ll;
typedef unsigned long long ull;
//const int maxn = 3e5 + 10;
const int turn[4][2] = {{1, 0}, { -1, 0}, {0, 1}, {0, -1}};
//priority_queue<int, vector<int>, less<int>> que;
//next_permutation
ll n;
ll num[200005];
ll t[200005];
vector<int> number[200005];
int lowbit(int x)
{
        return x & (-x);
}
void update(int x, ll p)
{
        while (x <= n)
        {
                t[x] += p;
                x += lowbit(x);
        }
        return;
}
ll sum(int k)
{
        ll ans = 0;
        while (k > 0)
        {
                ans += t[k];
                k -= lowbit(k);
        }
        return ans;
}
int main()
{
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
                scanf("%lld", &num[i]);
                num[i] = min(num[i], n);
                number[num[i]].pb(i);
                update(i, 1);
        }
        ll anser = 0;
        for (int i = 1; i <= n; i++)
        {
                anser += sum(num[i]);
                for (auto j : number[i])
                {
                        update(j, -1);
                }
        }
        for (int i = 1; i <= n; i++)
        {
                if (num[i] >= i)
                {
                        anser--;
                }
        }
        cout << anser / 2 << endl;
        return 0;
}
View Code

 

posted @ 2018-04-06 16:36  Aragaki  阅读(292)  评论(0编辑  收藏  举报