hdu 5786 Interval 区间gcd求和

#include <bits/stdc++.h>

using namespace std;

const int N = 80000+5;
const int MOD = 1e9+7;

int m;
vector<int> vt[N], com[N];
vector<pair<int,int> > prefix[N], suffix[N];
bool mark[N];
int g[N], pre_cnt[N], suf_cnt[N];
int fac[N], ff[N], ans[N];

int gcd(int a, int b) {
    return b ? gcd(b, a%b) : a;
}

inline void Add(int &x, int y) {
    x += y;
    if(x >= MOD) x -= MOD;
}

int a[N], nxt[N], val[N];
int gao(int id) {
    int n = vt[id].size();
    for(int i = 1;i <= n; i++) a[i] = vt[id][i-1];
    int ret = 0;
    for(int i = 1;i <= n; i++) {
        nxt[i] = i; val[i] = a[i];
        int cur = i;
        while(cur) {
            val[cur] = gcd(val[cur], a[i]);
            while(nxt[cur]-1 > 0 && gcd(a[i], val[nxt[cur]-1]) == val[cur]) {
                nxt[cur] = nxt[nxt[cur]-1];
            }
            Add(ret, 1ll*val[cur]*(cur-nxt[cur]+1)%MOD);
            cur = nxt[cur]-1;
        }
    }
    return ret;
}

int solve() {
    int mx = 0;
    for(int i = 0;i < m; i++)
        for(int j = 0;j < vt[i].size(); j++)
            mx = max(mx, vt[i][j]);
    for(int i = 0;i < m; i++) {
        g[i] = 0;
        for(int j = 0;j < vt[i].size(); j++) {
            mx = max(mx, vt[i][j]);
            g[i] = gcd(g[i], vt[i][j]);
            int nxt = j;
            while(nxt+1<vt[i].size() && vt[i][nxt+1]%g[i]==0) nxt++;
            prefix[g[i]].push_back({i,nxt-j+1});
            j = nxt;
        }
        com[g[i]].push_back(i);
        g[i] = 0;
        for(int j = vt[i].size()-1;j >= 0; j--) {
            g[i] = gcd(g[i], vt[i][j]);
            int nxt = j;
            while(nxt-1>=0 && vt[i][nxt-1]%g[i]==0) nxt--;
            suffix[g[i]].push_back({i,j-nxt+1});
            j = nxt;
        }
    }
    for(int i = 0;i < m; i++) mark[i] = 0;
    int ret = 0;
    for(int i = mx;i >= 1; i--) {
        ans[i] = 0;
        int cnt = 0, sum = 0, sum2 = 0;
        for(int j = i;j <= mx; j += i) {
            for(int k = 0;k < com[j].size(); k++) {
                int cur = com[j][k];
                if(!mark[cur]) {
                    cnt++;
                    mark[cur] = 1;
                    sum += vt[cur].size();
                    Add(sum2, 1ll*vt[cur].size()*vt[cur].size()%MOD);
                }
            }
        }
        if(cnt >= 2) {
            for(int j = 0;j <= cnt-2; j++) {
                int tmp = (1ll*sum*sum-sum2)%MOD;
                if(tmp < 0) tmp += MOD;
                tmp = 1ll*tmp*fac[cnt-2]%MOD*ff[cnt-2-j]%MOD*fac[m-j-2+1]%MOD;
                Add(ans[i], tmp);
            }
        }
        for(int j = i;j <= mx; j += i) {
            for(int k = 0;k < prefix[j].size(); k++) if(!mark[prefix[j][k].first]){
                pre_cnt[prefix[j][k].first] += prefix[j][k].second;
            }
            for(int k = 0;k < suffix[j].size(); k++) if(!mark[suffix[j][k].first]){
                suf_cnt[suffix[j][k].first] += suffix[j][k].second;
            }
        }
        int pre_sum = 0, suf_sum = 0, del_sum = 0;
        for(int j = i;j <= mx; j += i) {
            for(int k = 0;k < prefix[j].size(); k++) if(!mark[prefix[j][k].first]){
                int cur = prefix[j][k].first;
                pre_sum += pre_cnt[cur];
                suf_sum += suf_cnt[cur];
                Add(del_sum, 1ll*pre_cnt[cur]*suf_cnt[cur]%MOD);
                mark[cur] = 1;
            }
            for(int k = 0;k < suffix[j].size(); k++) if(!mark[suffix[j][k].first]){
                int cur = suffix[j][k].first;
                pre_sum += pre_cnt[cur];
                suf_sum += suf_cnt[cur];
                Add(del_sum, 1ll*pre_cnt[cur]*suf_cnt[cur]%MOD);
                mark[cur] = 1;
            }
        }
        for(int j = 0;j < cnt; j++) {
            int tmp = 1ll*sum*(pre_sum+suf_sum)%MOD;
            tmp = 1ll*tmp*fac[cnt-1]%MOD*ff[cnt-1-j]%MOD*fac[m-j-2+1]%MOD;
            Add(ans[i], tmp);
        }
        for(int j = 0;j <= cnt; j++) {
            int tmp = (1ll*pre_sum*suf_sum-del_sum)%MOD;
            if(tmp < 0) tmp += MOD;
            tmp = 1ll*tmp*fac[cnt]%MOD*ff[cnt-j]%MOD*fac[m-j-2+1]%MOD;
            Add(ans[i], tmp);
        }
        for(int j = i;j <= mx; j += i) {
            if(j > i) ans[i] -= ans[j];
            if(ans[i] < 0) ans[i] += MOD;
            for(int k = 0;k < com[j].size(); k++)
                mark[com[j][k]] = 0;
            for(int k = 0;k < prefix[j].size(); k++) {
                int cur = prefix[j][k].first;
                mark[cur] = pre_cnt[cur] = suf_cnt[cur] = 0;
            }
            for(int k = 0;k < suffix[j].size(); k++) {
                int cur = suffix[j][k].first;
                mark[cur] = pre_cnt[cur] = suf_cnt[cur] = 0;
            }
        }
        Add(ret, 1ll*ans[i]*i%MOD);
    }
    int add_ret = 0;
    for(int i = 0;i < m; i++) {
        Add(add_ret, gao(i)*1ll*fac[m]%MOD);
    }
    for(int i = 0;i <= mx; i++) {
        com[i].clear();
        prefix[i].clear();
        suffix[i].clear();
    }
    return (ret+add_ret)%MOD;
}

void init(int n) {
    fac[0]=fac[1]=ff[0]=ff[1] = 1;
    for(int i = 2;i <= n; i++) {
        fac[i] = 1ll*fac[i-1]*i%MOD;
        ff[i] = 1ll*(MOD-MOD/i)*ff[MOD%i]%MOD;
    }
    for(int i = 2;i <= n; i++) ff[i] = 1ll*ff[i-1]*ff[i]%MOD;
}

int main() {
    init(N-1);
//    freopen("data1.in", "r", stdin);
//    freopen("data2.out", "w", stdout);
    while(scanf("%d", &m) == 1) {
        int num, x;
        for(int i = 0;i < m; i++) {
            scanf("%d", &num);
            vt[i].clear();
            for(int j = 0;j < num; j++) {
                scanf("%d", &x);
                vt[i].push_back(x);
            }
        }
        printf("%d\n", solve());
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值