zoukankan      html  css  js  c++  java
  • 2018“百度之星”程序设计大赛

    没有兄弟的舞会

     
     Accepts: 928
     
     Submissions: 2446
     Time Limit: 2000/1000 MS (Java/Others)
     
     Memory Limit: 65536/65536 K (Java/Others)
    Problem Description

    度度熊、光羽、带劲三个人是好朋友。

    度度熊有一棵nn个点的有根树,其中1号点为树根。除根节点之外,每个点都有父节点,记ii号点的父节点为fa[i]fa[i]。

    度度熊称点ii和点jj是兄弟(其中i eq jij)当且仅当fa[i]=fa[j]fa[i]=fa[j]。

    ii个点的权值为A_iAi​​。现要求选出一个点集,该点集合法当且仅当点集中至多只有一对兄弟。

    度度熊想知道,在所有可行的点集中,权值和最大以及最小的点集权值和分别是多少?

    Input

    第一行一个数,表示数据组数TT。

    每组数据第一行一个整数nn;第二行n-1n1个数,表示fa[2],fa[3],..,fa[n]fa[2],fa[3],..,fa[n];第三行nn个数,表示A_iAi​​。

    数据组数T=100,满足:

    • 1 le n le 10^51n105​​
    • -10^9 le A_i le 10^9109​​Ai​​109​​
    • 1 le fa[i] < i1fa[i]<i

    其中90%的数据满足n le 1000n1000。

    Output

    每组数据输出一行,每行包含两个数,分别表示权值和的最大值和最小值。

    Sample Input
    2
    5
    1 1 2 2 
    -4 -4 -1 -2 -5 
    5
    1 1 3 2 
    -1 -4 2 0 -2 
    Sample Output
    0 -15
    2 -7

    这个对我来说有点hard啊,我比较傻,要选的是点集,不一定是子树,所以即使是树形dp也不是全都可以选的,所以可以直接sort之后取一个就好了

    另外一个直接找就好了

    #include<stdio.h>
    #include<bits/stdc++.h>
    using namespace std;
    #define lson l,(l+r)/2,rt<<1
    #define rson (l+r)/2+1,r,rt<<1|1
    #define dbg(x) cout<<#x<<" = "<< (x)<< endl
    #define pb push_back
    #define fi first
    #define se second
    #define ll long long
    #define sz(x) (int)(x).size()
    #define pll pair<long long,long long>
    #define pii pair<int,int>
    #define pq priority_queue
    const int N=1e5+5,MD=1e9+7,INF=0x3f3f3f3f;
    const ll LL_INF=0x3f3f3f3f3f3f3f3f;
    const double eps=1e-9,e=exp(1),PI=acos(-1.);
    vector<ll>G[N];
    ll a[N],x;
    int main()
    {
        ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
        int T,n;
        cin>>T;
        while(T--)
        {
            cin>>n;
            for(int i=2; i<=n; i++)cin>>a[i];
            for(int i=1; i<=n; i++)cin>>x,G[a[i]].push_back(x);
            ll ma=0,mi=0,minx=1e9,maxx=-1e9;
            for(int i=0; i<=n; i++)
            {
                sort(G[i].begin(),G[i].end());
                int len=G[i].size();
                if(len)
                {
                    ma=max(ma,ma+G[i][len-1]),mi=min(mi,mi+G[i][0]);
                    if(len>1)minx=min(minx,G[i][1]),maxx=max(maxx,G[i][len-2]);
                }
            }
            mi=min({mi,mi+minx,0LL}),ma=max({ma,maxx+ma,0LL});
            cout<<ma<<" "<<mi<<"
    ";
            for(int i=0; i<=n; i++)G[i].clear();
        }
        return 0;
    }

    带劲的and和

     
     Accepts: 791
     
     Submissions: 2435
     Time Limit: 2000/1000 MS (Java/Others)
     
     Memory Limit: 65536/65536 K (Java/Others)
    Problem Description

    度度熊专门研究过“动态传递闭包问题”,他有一万种让大家爆蛋的方法;但此刻,他只想出一道简简单单的题——至繁,归于至简。

    度度熊有一张n个点m条边的无向图,第ii个点的点权为v_ivi​​。

    如果图上存在一条路径使得点ii可以走到点jj,则称i,ji,j是带劲的,记f(i,j)=1f(i,j)=1;否则f(i,j)=0f(i,j)=0。显然有f(i,j) = f(j,i)f(i,j)=f(j,i)。

    度度熊想知道求出: sum_{i=1}^{n-1} sum_{j=i+1}^{n} f(i,j) imes max(v_i, v_j) imes (v_i & v_j)i=1n1​​j=i+1n​​f(i,j)×max(vi​​,vj​​)×(vi​​&vj​​)

    其中&&是C++中的and位运算符,如1&3=1, 2&3=2。

    请将答案对10^9+7109​​+7取模后输出。

    Input

    第一行一个数,表示数据组数TT。

    每组数据第一行两个整数n,mn,m;第二行nn个数表示v_ivi​​;接下来mm行,每行两个数u,vu,v,表示点uu和点vv之间有一条无向边。可能有重边或自环。

    数据组数T=50,满足:

    • 1 le n,m le 1000001n,m100000
    • 1 le v_i le 10^91vi​​109​​。

    其中90%的数据满足n,m le 1000n,m1000。

    Output

    每组数据输出一行,每行仅包含一个数,表示带劲的and和。

    Sample Input
    1
    5 5
    3 9 4 8 9 
    2 1
    1 3
    2 1
    1 2
    5 2
    Sample Output
    99

    其实就是每一个联通块要算贡献,这个联通块是可以用二进制压缩的,所以并查集找出联通块直接暴力就好了

    #include<stdio.h>
    #include<bits/stdc++.h>
    using namespace std;
    #define lson l,(l+r)/2,rt<<1
    #define rson (l+r)/2+1,r,rt<<1|1
    #define dbg(x) cout<<#x<<" = "<< (x)<< endl
    #define pb push_back
    #define fi first
    #define se second
    #define ll long long
    #define sz(x) (int)(x).size()
    #define pll pair<long long,long long>
    #define pii pair<int,int>
    #define pq priority_queue
    const int N=1e5+5,MD=1e9+7,INF=0x3f3f3f3f;
    const ll LL_INF=0x3f3f3f3f3f3f3f3f;
    const double eps=1e-9,e=exp(1),PI=acos(-1.);
    int fa[N],v[N];
    vector<int>G[N];
    int find(int x)
    {
        return x==fa[x]?x:(fa[x]=find(fa[x]));
    }
    void la(int x,int y)
    {
        x=find(x),y=find(y);
        if(x!=y)fa[x]=y;
    }
    int bit[31];
    ll lb(vector<int>v)
    {
        sort(v.begin(),v.end());
        ll ans=0,sum[31]= {0};
        for(auto t:v)
            for(int j=0; j<30; j++)
            {
                if(t&bit[j])
                {
                    ans=(ans+t*1LL*sum[j]%MD*bit[j]%MD)%MD;
                    sum[j]++;
                }
            }
        return ans;
    }
    int main()
    {
        ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
        for(int i=0; i<30; i++)bit[i]=1<<i;
        int T,n,m;
        cin>>T;
        while(T--)
        {
            cin>>n>>m;
            for(int i=1; i<=n; i++)cin>>v[i];
            for(int i=1; i<=n; i++)fa[i]=i;
            for(int i=0,u,v; i<m; i++)
                cin>>u>>v,la(u,v);
            for(int i=1; i<=n; i++)G[find(i)].push_back(v[i]);
            int ans=0;
            for(int i=1; i<=n; i++)
            {
                if(G[i].size()==0)continue;
                ans=(ans+lb(G[i]))%MD;
            }
            cout<<ans<<"
    ";
            for(int i=1; i<=n; i++)G[i].clear();
        }
        return 0;
    }

    序列期望

     
     Accepts: 545
     
     Submissions: 1163
     Time Limit: 2000/1000 MS (Java/Others)
     
     Memory Limit: 65536/65536 K (Java/Others)
    Problem Description

    "看似随机,实则早已注定"——光羽

    度度熊有nn个随机变量x_1,x_2,...,x_nx1​​,x2​​,...,xn​​。给定区间[l_1, r_1],...,[l_n, r_n][l1​​,r1​​],...,[ln​​,rn​​],变量x_ixi​​的值会等概率成为区间[l_i, r_i][li​​,ri​​]中的任意一个整数。

    显然这nn个随机变量的值会有一共prod_{i=1}^{n} (r_i - l_i + 1)i=1n​​(ri​​li​​+1) 种情况,且每种情况出现的概率为prod_{i=1}^{n} frac{1}{r_i - l_i + 1}i=1n​​ri​​li​​+11​​ 。

    对于某种情况,令h= max{ x_1,x_2,...,x_n}h=max{x1​​,x2​​,...,xn​​},定义这种情况的权值为:prod_{i=1}^{n} (h - x_i + 1)i=1n​​(hxi​​+1).

    度度熊想知道权值的期望是多少?请将答案对10^9 + 7109​​+7取模后输出。

    PS:不清楚期望是啥?为什么不问问神奇的百度呢?

    Input

    第一行一个数,表示数据组数TT。

    每组数据第一行一个整数nn;接下来nn行,每行两个数,表示l_ili​​和r_iri​​。

    数据组数T=100,满足:

    • 1 le n le 1001n100
    • 1 le l_i le r_i le 10^41li​​ri​​104​​

    其中70%的数据满足r_i le 100ri​​100。

    Output

    每组数据输出一行,每行仅包含一个数,表示期望。

    假设答案为frac{p}{q}qp​​,请输出p imes q^{-1} ~mod~10^9+7p×q1​​ mod 109​​+7,此处q^{-1}q1​​为qq的逆元。

    Sample Input
    2
    3
    2 5
    2 4
    2 5
    3
    1 1
    2 3
    1 1
    Sample Output
    875000012
    500000010
    Hint
    第二组数据的解释:序列只有两种情况(1,2,1)和(1,3,1),权值分别为2*1*2=4和3*1*3=9,答案为(4+9)/2,在模域下为500000010。
    这个题目看起来好像不可做,其实就是简单的期望,我们只要想到权值的统计方法就好了
    显然我们可以枚举最大的区间
    卡常劝退,比赛都能过的啊
    #include<stdio.h>
    #include<algorithm>
    typedef long long ll;
    const int MD=1e9+7;
    int l[105],r[105];
    ll w[105],v[10002];
    int main()
    {
        v[0]=v[1]=1;
        for(int i=2; i<10002; i++)v[i]=v[MD%i]*(MD-MD/i)%MD;
        int T,n,m;
        scanf("%d",&T);
        while(T--)
        {
            int L=0,R=0;
            ll ans=0;
            scanf("%d",&n);
            for(int i=0; i<n; i++)scanf("%d%d",&l[i],&r[i]),L=std::max(L,l[i]),R=std::max(R,r[i]);
            auto la=[&](long long x, long long y)
            {
                return (x+y)*(y-x+1)%MD*v[2]%MD;
            };
            for(int i=L; i<=R; i++)
            {
                ll t=1;
                w[n]=1;
                for(int j=0,x,y; j<n; j++)
                {
                    x=std::max(2,i-r[j]+1),y=i-l[j]+1;
                    w[j]=la(x,y);
                }
                for(int j=n-1; j>=0; j--)w[j]=w[j]*w[j+1]%MD;
                for(int j=0,x,y; j<n; j++)
                {
                    if(r[j]>=i)ans=(ans+t*w[j+1])%MD;
                    x=std::max(1,i-r[j]+1),y=i-l[j]+1;
                    t=t*la(x,y)%MD;
                }
            }
            for(int i=0; i<n; i++)ans=ans*v[r[i]-l[i]+1]%MD;
            printf("%lld
    ",ans);
        }
        return 0;
    }

     前面一定是2的倍数,为什么要乘上逆元,sb了,这样就不被卡常了

    #include<stdio.h>
    #include<algorithm>
    typedef long long ll;
    const int MD=1e9+7;
    int l[105],r[105];
    ll w[105],v[10002];
    ll la(ll x,ll y)
    {
        return (x+y)*(y-x+1)/2%MD;
    }
    int main()
    {
        v[0]=v[1]=1;
        for(int i=2; i<10002; i++)v[i]=v[MD%i]*(MD-MD/i)%MD;
        int T,n,m;
        scanf("%d",&T);
        while(T--)
        {
            int L=0,R=0;
            ll ans=0;
            scanf("%d",&n);
            for(int i=0; i<n; i++)scanf("%d%d",&l[i],&r[i]),L=std::max(L,l[i]),R=std::max(R,r[i]);
            for(int i=L; i<=R; i++)
            {
                ll t=1;
                w[n]=1;
                for(int j=0,x,y; j<n; j++)
                {
                    x=std::max(2,i-r[j]+1),y=i-l[j]+1;
                    w[j]=la(x,y);
                }
                for(int j=n-1; j>=0; j--)w[j]=w[j]*w[j+1]%MD;
                for(int j=0,x,y; j<n; j++)
                {
                    if(r[j]>=i)ans=(ans+t*w[j+1])%MD;
                    x=std::max(1,i-r[j]+1),y=i-l[j]+1;
                    t=t*la(x,y)%MD;
                }
            }
            for(int i=0; i<n; i++)ans=ans*v[r[i]-l[i]+1]%MD;
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    (PHP)redis Zset(有序集合 sorted set)操作
    (PHP)redis Set(集合)操作
    (PHP)redis Hash(哈希)操作
    (PHP)redis String(字符串)操作
    (PHP)redis List(列表)操作
    PHP连接 redis
    PHP json 对象 数组互相转换
    循环节长度 蓝桥杯
    三羊献瑞 蓝桥杯
    立方变自身
  • 原文地址:https://www.cnblogs.com/BobHuang/p/9501607.html
Copyright © 2011-2022 走看看