UVALive 7343 H - Design New Capital


题目描述:

If you go through history you will come across many fun facts about the capital city of a country.
In many countries the most famous or most populated or most industrialized cities are not declared
capital. For example, Zurich or Geneva is not capital of Switzerland it is Berne. In Australia the capital
is neither Melbourne nor Sydney, it is Canberra and guess what Canberra was built to be capital! In
Brazil Brasilia is capital not Rio.
Head of your country decided to redesign the capital. Dr. Krakow is appointed as the head architect
of this project. Having been in Europe and America, he has vast experience about city life. He wants
to lay roads like New York. That is, if you see from above, it will look like a big 2d grid. He wants
to build the parliament at (0, 0) coordinate of this grid. After that, he asks some people where would
they love to stay. Of course, it is not possible to allow to build homes anywhere the people like. There
are many constraints to consider. One of the constraints is the parliament has to be at the optimal
position. A position is optimal if summation of Manhattan distance to all the houses from the position
is minimum.
For example, suppose there are three proposals to build houses at following positions: (1, 1), (−1, −1)
and (2, 2). If Dr. Krakow approves to build houses at (1, 1) and (−1, −1) then (0, 0) would be optimal
position. But if he approves (1, 1) and (2, 2) then (0, 0) is no more optimal position. Please note, there
may be many optimal positions for some set of approval, but (0, 0) has to be one of them. Given some
proposals, help Dr. Krakow to figure out number of ways he can approve some of the proposals so that
parliament is at one of the optimal positions. Please note, there may be request for the same place
from different persons. In such case Dr. Krakow can approve none or all or some of these proposals.
When computing summation of Manhattan distance, all of the approved proposals are counted, that is,
if there are two approved proposals at the same place, then distance from this place to the parliament
will be counted twice.
Input
The first line of the input will contain a positive integer T (T ≤ 5). Hence T cases follow.
First line of the test case contains number of proposals n (1 ≤ n ≤ 105
). Hence n liness follow, each
describing a proposal x, y (−109 ≤ x, y ≤ 109 and xy ̸= 0).
Output
For each case print case number followed by space separated n numbers where i-th of these numbers
denotes number of ways you can accept i proposals. Since the answer can be very big you need to
present the solution in modulo 7340033.

题解:

1.其实就是中位数.
2.显然奇数不可能,偶数的话是对称4个区域有关系.
3.可以写出公式之后, 发现时卷积,用NTT

重点:

1.中位数,再推,写出公式来优化
2.NTT

代码:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

typedef long long ll;

const int M = 7340033;
const int maxn = 5e5 + 100;
const int key = 100000;

int c[5][maxn], num[5];
int a1[maxn], a2[maxn];
int x1[maxn], x2[maxn];
int rev[maxn], n;

int add(int a, int b) {
    int c = a + b;
    if(c >= M)
        c -= M;
    return c;
}
int sub(int a, int b) {
    if(a < b)
        a += M;
    return a - b;
}
int power(int x, int n) {
    int res = 1, tmp = x % M;
    while(n) {
        if(n & 1)
            res = (ll)res * (ll)tmp % M;
        tmp = (ll)tmp * (ll)tmp % M;
        n >>= 1;
    }
    return res;
}
int inverse(int x) {
    return power(x, M - 2);
}

void change(int y[], int len) {
    int i, j, k;
    for(i = 1, j = len / 2; i < len - 1; i++) {
        if(i < j) swap(y[i], y[j]);
        k = len / 2;
        while(j >= k) {
            j -= k;
            k /= 2;
        }
        if(j < k) j += k;
    }
}

void fft(int y[], int len, int on) {
    change(y, len);
    for(int h = 2; h <= len; h <<= 1) {
        int unit_p0 = power(3, (M - 1) / h);
        if(on == -1)
            unit_p0 = inverse(unit_p0);
        for(int j = 0; j < len; j += h) {
            int unit = 1;
            for(int k = j; k < j + h / 2; k++) {
                int u = y[k];
                int t = (ll)unit * (ll)y[k + h / 2] % M;
                y[k] = add(u, t);
                y[k + h / 2] = sub(u, t);
                unit = (ll)unit * (ll)unit_p0 % M;
            }
        }
    }
    if(on == -1) {
        int key = inverse(len);
        for(int i = 0; i < len; i++) {
            y[i] = (ll)y[i] * (ll)key %M;
        }
    }
}

void solve() {
    for(int i = 0; i < 4; i++) {
        int a = num[i];
        c[i][0] = 1;
        for(int j = 1; j <= key; j++) {
            if(j > a)
                c[i][j] = 0;
            else {
                c[i][j] = (ll)c[i][j - 1] * (ll)(a - j + 1) % M * (ll)rev[j] % M;
            }
        }
    }
    memset(a1, 0, sizeof(a1));
    memset(a2, 0, sizeof(a2));
    for(int i = 0; i <= key; i++) {
        a1[i] = (ll)c[0][i] * (ll)c[2][i] % M;
        a2[i] = (ll)c[1][i] * (ll)c[3][i] % M;
    }

    int len = key;
    int len1 = 1;
    while(len1 <2 * len) {
        len1 *= 2;
    }
    fft(a1, len1, 1);
    fft(a2, len1, 1);
    for(int i = 0; i < len1; i++) {
        a1[i] = (ll)a1[i] * (ll)a2[i] % M;
    }
    fft(a1, len1, -1);
    for(int i = 1; i <= n; i++) {
        if(i % 2 == 1)
            printf("0");
        else
            printf("%d", a1[i / 2]);
        if(i != n) printf(" ");
        else printf("\n");
    }
}

int main() {
    //freopen("h.txt", "r", stdin);
    for(int i = 1; i <= key; i++)
        rev[i] = inverse(i);
    int ncase;
    scanf("%d", &ncase);
    for(int _ = 1; _ <= ncase; _++) {
        printf("Case %d:\n", _);
        scanf("%d", &n);
        memset(num, 0, sizeof(num));
        for(int i = 1; i <= n; i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            if(x >= 0 && y >= 0)
                num[0]++;
            if(x <= 0 && y >= 0)
                num[1]++;
            if(x <=0 && y <= 0)
                num[2]++;
            if(x >=0 && y <= 0)
                num[3]++;
        }
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值