2018 icpc 徐州

Posted hyfer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018 icpc 徐州相关的知识,希望对你有一定的参考价值。

A

矩阵树定理可以用于最小生成树计数,最直观的做法就是求个mst,再用矩阵树定理求最小生成树个数,但是n<=1e5,显然不是o(n^3)可以做出来的。

考虑随机数据生成器,固定1e5的边,但是边权在unsigned long long的范围内随机指定,由样例看出,即使是点数很少的情况下,最多也只有一个生成树

于是,我们猜测,只需要做一遍最小生成树,并假定不会有更多的生成树就可以了。

#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int maxn = 100050;
const ull mod = 1000000007;
int f[maxn];
int findf(int x){
    return f[x] == x ? x : f[x] = findf(f[x]); 
}
int n,m;
ull k1,k2;
struct edge{
    int u;
    int v;
    ull w;
    friend bool operator < (edge a,edge b){
        return a.w < b.w;
    }
}e[maxn];
ull xorS(){
    ull k3 = k1,k4 = k2;
    k1 = k4;
    k3 ^= k3 << 23;
    k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
    return k2 + k4;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        cin>>n>>m>>k1>>k2;
        for(int i = 1;i <= m;i++){
            e[i].u = xorS() % n + 1;
            e[i].v = xorS() % n + 1;
            e[i].w = xorS();
        }
        sort(e+1,e+1+m);
        for(int i = 1;i <= n;i++){
            f[i] = i;
        }
        ull tot = 0;
        int uu,vv,cnt = 0;
        for(int i = 1;i <= m;i++){
            uu = e[i].u;
            vv = e[i].v;
            uu = findf(uu);
            vv = findf(vv);
            if(uu == vv) continue;
            else{
                cnt++;
                e[i].w %= mod;
                tot = (tot + e[i].w) % mod;
                f[uu] = vv;
            }
        }
        if(cnt != n-1) tot = 0;
        cout<<tot<<endl;
    }
    return 0;
}

G

选择k个路径,它们至少有一个交点,首先先把路径经过的点标记一下,对于一个点,它被选中,至少要有k个路径经过它。

这样就有一个需要考虑的地方,如果这k个路径有不止一个交点,就会被重复统计,如何去重?

两条路径的交点,只可能是树上连续的一段,所以多条路径的交点,也只能是树上的一段,对于一个方案,可以只在深度最小的那个点统计一次,而这个点,肯定是某个路径深度最小的点。

遍历每个点,新加进去以这个点为lca的路径,和经过这个点的其他路径联合起来算对方案的贡献。

如何快速计算一个点经过多少路径?可以让深度最深的点+1,走出这条路径或者达到交点(lca)时-1,也就是树上差分。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#define fo(i, l, r) for (long long i = l; i <= r; i++)
#define fd(i, l, r) for (long long i = r; i >= l; i--)
#define mem(x) memset(x, 0, sizeof(x))
#define ll long long
#define ld double
using namespace std;
const int maxn = 300050;
const ll mod = 1e9 + 7;
ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while (!(ch >= 0 && ch <= 9))
    {
        if (ch == -)
            f = -1;
        ch = getchar();
    };
    while (ch >= 0 && ch <= 9)
    {
        x = x * 10 + (ch - 0);
        ch = getchar();
    };
    return x * f;
}
int n, m, k;
vector<int> g[maxn];
int d[maxn];
int fa[maxn][25];
void dfs(int u, int f, int deep)
{
    d[u] = deep;
    fa[u][0] = f;
    int t = 0;
    while (fa[u][t] && fa[fa[u][t]][t])
    {
        fa[u][t + 1] = fa[fa[u][t]][t];
        t++;
    }
    int sz = (int)g[u].size() - 1, v;
    fo(i, 0, sz)
    {
        v = g[u][i];
        if (v == f)
            continue;
        dfs(v, u, deep + 1);
    }
}
int lca(int u, int v)
{
    if (d[u] < d[v])
        swap(u, v);
    int delta = d[u] - d[v];
    int t = 0;
    while (delta)
    {
        if (delta & 1)
            u = fa[u][t];
        t++;
        delta >>= 1;
    }
    if (u == v)
        return u;
    t = 0;
    while (t >= 0)
    {
        if (fa[u][t] != fa[v][t])
        {
            u = fa[u][t];
            v = fa[v][t];
            t++;
        }
        else
        {
            t--;
        }
    }
    return fa[u][0];
}
int addamt[maxn], cf[maxn], uu[maxn], vv[maxn];

ll fac[maxn], inv[maxn];
ll ans;
ll C(ll n, ll m)
{
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
void dfs2(int u)
{
    int v, sz = (int)g[u].size() - 1;
    fo(i, 0, sz)
    {
        v = g[u][i];
        if (v == fa[u][0])
            continue;
        dfs2(v);
        cf[u] += cf[v];
    }
}
int main()
{
    //freopen("data.in","r",stdin);
    fac[0] = fac[1] = 1;
    fo(i, 2, maxn - 1)
    {
        fac[i] = (fac[i - 1] * i) % mod;
    }
    inv[0] = inv[1] = 1;
    fo(i, 2, maxn - 1)
    {
        inv[i] = (mod - (mod / i)) * inv[mod % i] % mod;
    }
    fo(i, 2, maxn - 1)
    {
        inv[i] = (inv[i] * inv[i - 1]) % mod;
    }
    int T = read();
    while (T--)
    {
        memset(fa, 0, sizeof(fa));
        memset(d, 0, sizeof(d));
        ans = 0;
        n = read();
        m = read();
        k = read();
        fo(i, 1, n) g[i].clear();
        int u, v;
        fo(i, 1, n - 1)
        {
            u = read();
            v = read();
            g[u].push_back(v);
            g[v].push_back(u);
        }
        fo(i, 1, m)
        {
            uu[i] = read();
            vv[i] = read();
        }
        dfs(1, 0, 1);
        fo(i, 1, n) cf[i] = addamt[i] = 0;
        int zz, cd;
        fo(i, 1, m)
        {
            zz = lca(uu[i], vv[i]);
            addamt[zz]++;
            cf[uu[i]]++;
            cf[vv[i]]++;
            cf[zz]--;
            cf[fa[zz][0]]--;
        }
        dfs2(1);
        fo(i, 1, n)
        {
            cf[i] -= addamt[i];
            fo(j, 1, addamt[i])
            {
                
                
                if (j > k)
                    break;
                if (cf[i] >= k - j){
                    ans = (ans + C(cf[i], k - j) * C(addamt[i], j) % mod) % mod;
                }
            }
        }
        printf("%lld
", ans);
    }
    return 0;
}

H

如果区间的数量不大于颜色数,那么每个区间染上不同的颜色就可以了。

如果有断层,尽量染上缺少的颜色,如果区间比较多,如何确保染到一个最优的颜色?

某些颜色在大于某个位置就没有了,如果染上那个最早失效的颜色,就可能会使答案增大。

对于每个颜色,维护一个它消失的位置,每次取出那个消失位置最靠前的染色。

这个题spj有毛病,行尾有空格算你wa,是真的无语。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#define fo(i, l, r) for (long long i = l; i <= r; i++)
#define fd(i, l, r) for (long long i = r; i >= l; i--)
#define mem(x) memset(x, 0, sizeof(x))
#define ll long long
#define ld double
using namespace std;
const int maxn = 200050;
const ll mod = 1e9 + 7;
ll read()
{
    ll x = 0, f = 1;
    char ch = getchar();
    while (!(ch >= 0 && ch <= 9))
    {
        if (ch == -)
            f = -1;
        ch = getchar();
    };
    while (ch >= 0 && ch <= 9)
    {
        x = x * 10 + (ch - 0);
        ch = getchar();
    };
    return x * f;
}
struct dat{
    int p;
    ll v;
    friend bool operator < (dat a,dat b){
        return a.v > b.v;
    }
}now,nxt,col;
priority_queue<dat> q,ys;
ll n,k,ans[maxn],op[maxn],ed[maxn],cnt[maxn];
ll tot;
int main()
{
    int T=read();
    while(T--){
        tot=0;
        while(!q.empty())q.pop();
        while(!ys.empty())ys.pop();
        n=read();k=read();
        if(k>n)k=n;
        fo(i,1,n)ans[i]=0;
        fo(i,1,k)cnt[i]=0;
        int nowp=0,nowk=0;
        fo(i,1,n){
            now.p=i;
            now.v=read();
            q.push(now);
            op[i] = now.v;
            now.v=read();
            q.push(now);
            ed[i] = now.v;
        }
        fo(i,1,k){
            now.p=i;
            now.v=-1;
            ys.push(now);
        }
        while(!q.empty()){
            now=q.top();
            q.pop();
            if(ans[now.p]){
                cnt[ans[now.p]]--;
                if(cnt[ans[now.p]]==0) nowk--;
            }else{
                col=ys.top();
                ys.pop();
                ans[now.p] = col.p;
                cnt[col.p]++;
                if(cnt[col.p]==1) nowk++;
                col.v = max(col.v,(ll)ed[now.p]);
                ys.push(col);
            }
            nowp = now.v;
            if(!q.empty()){
                nxt=q.top();
                if(nxt.v == now.v) continue;
                else{
                    if(nowk >= k) tot += nxt.v - now.v;
                }
            }
        }
        printf("%lld
",tot);
        printf("%lld",ans[1]);
        fo(i,2,n) printf(" %lld",ans[i]);
        putchar(
);
    }
    return 0;
}

 

以上是关于2018 icpc 徐州的主要内容,如果未能解决你的问题,请参考以下文章

ACM-ICPC 2018 徐州赛区(网络赛)

Trace 2018徐州icpc网络赛 思维+二分

ACM-ICPC 2018 徐州赛区网络预赛

2018 icpc 徐州

ICPC2018徐州网络赛 Hard to prepare(dp)

ACM-ICPC 2018 徐州赛区网络预赛