2014牡丹江 現場賽 F zoj 3824 Fiber-optic Network

來源:互聯網
上載者:User

標籤:acm   zoj   

首先贊一下題目, 好題


題意:

Marjar University has decided to upgrade the infrastructure of school intranet by using fiber-optic technology. There are N buildings in the school. Each building will be installed with one router. These routers are connected by optical cables in such a way that there is exactly one path between any two routers.

Each router should be initialized with an operating frequency Fi before it starts to work. Due to the limitations of hardware and environment, the operating frequency should be an integer number within [Li, Ri]. In order to reduce the signal noise, the operating frequency of any two adjacent routers should be co-prime.

Edward is the headmaster of Marjar University. He is very interested in the number of different ways to initialize the operating frequency. Please write a program to help him! To make the report simple and neat, you only need to calculate the sum of Fi (modulo 1000000007) in all solutions for each router.


英文自己看, 大概意思就是一棵樹上每個點i可以給一個L[i] ~ R[i]的值, 相鄰的兩個點的值要互質, 問每個點的所有情況的值的和, mod 1000000007


大概思路就是枚舉一個點, 然後枚舉這個點上的值(i), 然後求出這樣的情況有多少種(dp[i]), 那麼這個點上的答案就是 dp[1] * 1 + dp[2] * 2 + dp[3] * 3 + .........

然後就是樹形dp了, 轉移方程就是 dp[i][j] =π{(∑{dp[t][k] | gcd(j, k) == 1}) | i 和 t 相鄰}

但是這樣轉移的複雜度是50 * 50000 * 50000, 就算15秒時限也會逾時

所以我們可以考慮用不互質的來轉移;

設s[i] = ∑dp[i][j]

那麼轉移方程就是   dp[i][j] =π{(s[i] - ∑{dp[t][k] | gcd(j, k) != 1}) | i 和 t 相鄰}

對於dp[i][j],我們可以把 j 質因數分解, 假設 j = p1^e1 * p2^e2 * p3^e3, 50000以內的數最多有6個不同的質因數;

然後我們記錄一下 div[i][k] = ∑{ dp[i][j] | j 是 k 的倍數}, 這個可以nlogn的複雜度處理出來;

這樣  ∑{dp[t][k] | gcd(j, k) != 1} = div[t][p1] + div[t][p2] + div[t][p3] - div[t][p1 * p2] - div[t][p1 * p3] - div[t][p2 * p3] + div[t][p1 * p2 * p3], 這樣可以用容斥原理算了, 複雜度最多為2 ^ 6;

這樣dp一次複雜度大概就是 50 * 50000 * (log50000 + 2^6);

要算50個點的話, 還是會逾時;

但是這是一顆樹, 對每個點都dp一次的話算了很多重複的東西, 所以我們不要每次都去全部dp一次, 例如算完i點的了, 要去算j點的, 假設i j相鄰, 那麼在dp數組中只有i和j的值有變化, 我們就只要再算這兩個點的dp轉移就夠了。

更多細節請看代碼:


#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <ctime>#include <vector>using namespace std;typedef long long LL;const int N = 50009;const LL M = 1000000007;inline void addIt(int &a, int b){    a += b;    if(a >= M) a -= M;}inline int sub(int a, int b){    a -= b;    if(a < 0) a += M;    if(a >= M) a -= M;    return a;}struct Num{    int p[11];    int allp;}num[N];struct Data{    int dp[N], div[N], all;}data[55], fb[55];int L[55], R[55];int ans[55];int n;vector<int> e[55];bool vis[55];int rcn, rcv;void print(){    for(int i = 0; i < n; i++)    {        printf("i = %d\n", i);        for(int j = 0; j < 6; j++) printf("dp[%d] = %d\n", j, data[i].dp[j]);    }}int rc(int i, int xs){    int t, r = 0;    for(; i < num[rcn].allp; i++)    {        if(xs * num[rcn].p[i] <= R[rcv]) t = data[rcv].div[xs * num[rcn].p[i]];        else t = 0;        //printf("***%d, t = %d\n", xs * num[rcn].p[i], t);        addIt(r, sub(t, rc(i + 1, xs * num[rcn].p[i])));    }    //printf("r = %d\n", r);    return r;}void dfsTree(int pre, int now){    if(vis[now]) return;    vis[now] = true;    int i, siz = e[now].size();    for(i = 0; i < siz; i++) dfsTree(now, e[now][i]);    if(pre >= 0 && siz <= 1) for(i = L[now]; i <= R[now]; i++) data[now].dp[i] = 1;    else for(i = L[now]; i <= R[now]; i++)    {        data[now].dp[i] = 1;        for(int j = 0; j < siz; j++) if(e[now][j] != pre)        {            rcn = i;            rcv = e[now][j];            data[now].dp[i] = (LL)(data[now].dp[i]) * sub(data[e[now][j]].all, rc(0, 1)) % M;        }    }    data[now].all = 0;    for(i = 1; i <= R[now]; i++)    {        data[now].div[i] = 0;        for(int j = i; j <= R[now]; j += i) if(j >= L[now]) addIt(data[now].div[i], data[now].dp[j]);        if(i >= L[now]) addIt(data[now].all, data[now].dp[i]);    }}void dfs(int pre, int now, int deep){    dfsTree(-1, now);    //if(now == 1) print();    int i, siz = e[now].size();    ans[now] = 0;    for(i = L[now]; i <= R[now]; i++) addIt(ans[now], (LL)data[now].dp[i] * i % M);    //fb[deep] = data[now];    //vis[now] = false;    for(i = 0; i < siz; i++) if(e[now][i] != pre)    {        vis[e[now][i]] = false;        fb[deep] = data[e[now][i]];        vis[now] = false;        dfs(now, e[now][i], deep + 1);        data[e[now][i]] = fb[deep];        vis[e[now][i]] = true;    }}void init(){    int i, j, k;    for(i = 0; i < N; i++) num[i].allp = 0;    for(i = 2; i < N; i++) if(num[i].allp == 0) for(j = i; j < N; j += i) num[j].p[num[j].allp++] = i;}int main(){    //freopen("13F.in", "r", stdin);    init();    int T;    scanf("%d", &T);    while(T--)    {        scanf("%d", &n);        int i, j, k;        for(i = 0; i < n; i++)        {            scanf("%d", &L[i]);        }        for(i = 0; i < n; i++)        {            scanf("%d", &R[i]);            e[i].clear();        }        for(i = 0; i < n - 1; i++)        {            scanf("%d %d", &j, &k);            j--;            k--;            e[j].push_back(k);            e[k].push_back(j);        }        memset(vis, false, sizeof(vis));        memset(data, 0, sizeof(data));        dfsTree(-1, 0);        //print();        dfs(-1, 0, 0);        for(i = 0; i < n - 1; i++) printf("%d ", ans[i]); printf("%d\n", ans[i]);    }    return 0;}


2014牡丹江 現場賽 F zoj 3824 Fiber-optic Network

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.