zoukankan      html  css  js  c++  java
  • 2.23模拟赛

    浪了一发普及模拟赛

    题面见此

    【样例输入】

    4

    1 1

    2 1

    1 1

    【样例输出】

    20

    【数据规模和范围】

    对于 30%的数据,n≤1000。

    对于另外 30%的数据,bi=1。

    对于 100%的数据,n≤1 000 000,bi≤1000。

    sol:单边记贡献,(x,y)边的贡献就是 Size[y]*(n-Size[y])*Dis[x][y],因为父亲都小于当前点,直接倒着跑一遍记Size就可以了,如果无序的话可以用拓扑

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll S=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            S=(S<<3)+(S<<1)+(ch-'0'); ch=getchar();
        }
        return (f)?(-S):(S);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10); putchar(x%10+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=1000005;
    int n,Father[N],Size[N];
    int Val[N];
    int main()
    {
        freopen("fst.in","r",stdin);
        freopen("fst.out","w",stdout);
        int i;
        ll ans=0;
        R(n);
        for(i=1;i<=n;i++)
        {
            Size[i]=1;
        }
        for(i=2;i<=n;i++)
        {
            Father[i]=read(); Val[i]=read();
        }
        for(i=n;i>1;i--)
        {
            Size[Father[i]]+=Size[i];
        }
        for(i=2;i<=n;i++)
        {
            ans+=1ll*Val[i]*Size[i]*(n-Size[i]);
        }
        Wl(ans<<1);
        return 0;
    }
    /*
    input
    5
    1 2
    2 4
    2 1
    4 4
    output
    92
    
    input
    5
    1 5
    1 5
    2 3
    2 5
    output
    164
    */
    View Code

    2.贰(fstagain)

    【题目描述】

    给你一个长度为 n 的序列,有 m 次询问,让你求区间 gcd。

    【输入格式】

    输入文件为 fstagain.in。 第一行两个正整数 n 和 m。 第二行 n 个正整数 ai,保证 ai≤1 000 000 000。 接下来 m 行,每行两个正整数 l 和 r,询问序列中 l 到 r 的 gcd。

    【输出格式】

    输出文件为 fst.in。 输出 m 行,表示查询的结果。

    【样例输入】

    3 2

    3 6 8

    1 2

    2 3

    【样例输出】

    3

    2

    【数据规模和范围】

    对于 30%的数据,n,m≤1000。

    对于 60%的数据,n≤1000。

    对于 100%的数据,n,m≤100000。

     

    sol:因为重复没关系,ST表可以搞,线段树应该也可以做(反正是模板),我写了分块(反正都能过)

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll S=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            S=(S<<3)+(S<<1)+(ch-'0'); ch=getchar();
        }
        return (f)?(-S):(S);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10); putchar(x%10+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=100005,B=355;
    int n,m,a[N];
    int Block,cnt,L[B],R[B],Gcd[B],Pos[N];
    inline int gcd(int x,int y)
    {
        return (!y)?(x):(gcd(y,x%y));
    }
    inline void Pre()
    {
        int i,j;
        Block=sqrt(n);
        cnt=n/Block+(bool)(n%Block);
        for(i=1;i<=cnt;i++)
        {
            L[i]=R[i-1]+1;
            R[i]=L[i]+Block-1;
        }
        R[cnt]=n;
        for(i=1;i<=cnt;i++)
        {
            Gcd[i]=a[L[i]];
            Pos[L[i]]=i;
            for(j=L[i]+1;j<=R[i];j++)
            {
                Pos[j]=i;
                Gcd[i]=gcd(Gcd[i],a[j]);
            }
        }
        return;
    }
    inline int Solve(int l,int r)
    {
        int i;
        int ql=Pos[l],qr=Pos[r];
        if(ql+1>=qr)
        {
            int ans=a[l];
            for(i=l+1;i<=r;i++)
            {
                ans=gcd(ans,a[i]);
            }
            return ans;
        }
        else
        {
            int ans=a[l];
            for(i=l+1;i<L[ql+1];i++)
            {
                ans=gcd(ans,a[i]);
            }
            for(i=ql+1;i<qr;i++)
            {
                ans=gcd(ans,Gcd[i]);
            }
            for(i=L[qr];i<=r;i++)
            {
                ans=gcd(ans,a[i]);
            }
            return ans;
        }
    }
    int main()
    {
        freopen("fstagain.in","r",stdin);
        freopen("fstagain.out","w",stdout);
        int i;
        R(n); R(m);
        for(i=1;i<=n;i++)
        {
            R(a[i]);
        }
        Pre();
        for(i=1;i<=m;i++)
        {
            int l=read(),r=read();
            Wl(Solve(l,r));
        }
        return 0;
    }
    /*
    input
    3 2
    3 6 8
    1 2
    2 3
    output
    3
    2
    */
    View Code

    3.叁(fstalways)

    【题目描述】

    有 4 种硬币,面值分别为 c1,c2,c3,c4。某人去商店买东西,去 了 tot 次。每次带 di 枚 ci 硬币,买 s 的价值的东西。求每次有多少 种付款方法。

    【输入格式】

    输入文件为 fstalways.in。 第一行 5 个正整数 c1,c2,c3,c4,tot。 接下来 tot 行,每行 5 个正整数表示的 d1,d2,d3,d4,s。

    【输出格式】

    输出文件为 fstalways.out。 输出 tot 行,表示每次的方案数。

    【样例输入】

    1 2 5 10 2

    3 2 3 1 10

    1000 2 2 2 900

    【样例输出】

    4

    27

    【数据规模和范围】

    对于 30%的数据,di≤10。

    对于 50%的数据,s,tot≤1000。

    对于 100%的数据,s≤1000000,tot≤100000。

    sol:先跑一遍没有 di 限制的背包,然后容斥,奇加偶减(这是套路)

    容斥过程:对于S,选择第 i 种硬币超限的方案数就是 dp[S-(di+1)*c[i]],因为是完全背包,剩下的S-(di+1)*c[i]可以随便选,然而就算一个 i 也不选也是会超限的

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    int C[5],D[5];
    ll dp[1000005];
    int main()
    {
        freopen("fstalways.in","r",stdin);
        freopen("fstalways.out","w",stdout);
        int i,j,T,Sum;
        ll ans=0;
        for(i=1;i<=4;i++)
        {
            R(C[i]);
        }
        R(T);
        dp[0]=1;
        for(i=1;i<=4;i++)
        {
            for(j=C[i];j<=1000000;j++)
            {
                dp[j]+=dp[j-C[i]];
            }
        }
        while(T--)
        {
            ans=0;
            for(i=1;i<=4;i++)
            {
                R(D[i]);
            }
            R(Sum);
            for(i=0;i<=15;i++)
            {
                int SS=Sum,Bo=1;
                for(j=1;j<=4;j++) if(i&(1<<(j-1)))
                {
                    SS-=C[j]*(D[j]+1);
                    Bo^=1;
                }
                if(SS<0) continue;
                if(Bo) ans+=dp[SS]; else ans-=dp[SS];
            }
            Wl(ans);
        }
        return 0;
    }
    /*
    input
    1 2 5 10 2
    3 2 3 1 10
    1000 2 2 2 900
    output
    4
    27
    */
    View Code

    4.肆(fstforever)

    【题目描述】

    给定一棵 n 个节点的有根树,编号依次为 1 到 n,其中 1 号点为 根节点。每个点有一个权值 vi。 现在,你需要选择尽可能多的节点,满足以下的性质:对于任意 两个点 i,j,如果 i 在树上是 j 的祖先,那么 vi>vj。请计算可选的最 多的点数。

    【输入格式】

    输入文件为 fstforever.in。 第一行一个正整数 n。 第二行 n-1 个正整数 ai,表示 i+1 的父亲(ai≤i+1)。 第三行 n 个整数,第 i 个整数表示 vi。 【输出格式】 输出文件为 fstforever.out。 输出一个整数,为最多的点数。

    【样例输入】

    6

    1 1 1 1 1

    3 1 2 3 4 5

    【样例输出】

    5

    【数据规模和范围】

    对于 30%的数据,n≤20。

    对于 50%的数据,保证 n≤3000。

    对于另外 20%的数据,保证 ai=i。

    对于 100%的数据,vi≤1 000 000 000,n≤200000。

    sol:对于一条链,就是跑最长上升子序列,在一棵树上是 ,我们发现对于一个非叶子节点,他所有儿子都是等价的,用multiset启发式合并就可以了

    其实着重解释一下一种求LIS的方法 为什么是对的

    方法是这样的:维护一个multiset,即每次新加一个元素时,在维护的multiset中找到比它大的第一个元素,替换,(如果没有就直接加入这个元素)最后multiset的长度就是LIS的长度。

    为什么是替换掉比他大的第一个,而不是把所有比他大的都去掉呢?

    (1)如果被替换掉的是multiset里最大的元素,就表示当前点的值加入当前维护的LIS中,并在维护的LIS中删除被替换的值

    (2)如果替换之后,multiset里有比当前节点的值更大的元素,就表示不将当前节点的值加入LIS,LIS的长度不变

    (3)如果没有更大的元素,就直接加入当前的值,LIS长度+1。

    每次新加入元素的时候其实只跟当前LIS里最大的元素有关

    要么是加入新元素,最大元素变小,LIS长度不变

    要么是加入新元素、最大元素变大、LIS长度+1

    要么是不加入新元素、LIS不变

    #include <bits/stdc++.h>
    using namespace std;
    typedef int ll;
    inline ll read()
    {
        ll s=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=200005,M=400005;
    int n,Val[N];
    struct Tree
    {
        int tot,Next[M],to[M],head[N];
        inline void add(int x,int y)
        {
            Next[++tot]=head[x];
            to[tot]=y;
            head[x]=tot;
            return;
        }
        multiset<int>S[N];
        inline void Merg(int x,int y)
        {
            multiset<int>::iterator it;
            if(S[x].size()<S[y].size()) swap(S[x],S[y]);
            for(it=S[y].begin();it!=S[y].end();it++)
            {
                S[x].insert(*it);
            }
            return;
        }
        inline void dfs(int x)
        {
            int i;
            for(i=head[x];i;i=Next[i])
            {
                dfs(to[i]);
                Merg(x,to[i]);
            }
            if(S[x].size())
            {
                multiset<int>::iterator it;
                it=S[x].lower_bound(Val[x]);
                if(it!=S[x].end())
                {
                    S[x].erase(it);
                }
            }
            S[x].insert(Val[x]);
            return;
        }
        inline void Init()
        {
            tot=0;
            memset(head,0,sizeof head);
            return;
        }
    }T;
    int main()
    {
        freopen("fstforever.in","r",stdin);
        freopen("fstforever.out","w",stdout);
        int i;
        R(n);
        T.Init();
        for(i=2;i<=n;i++)
        {
            T.add(read(),i);
        }
        for(i=1;i<=n;i++)
        {
            R(Val[i]);
        }
        T.dfs(1);
        Wl(T.S[1].size());
        return 0;
    }
    /*
    input
    6
    1 1 1 1 1
    3 1 2 3 4 5
    output
    5
    */
    View Code
  • 相关阅读:
    Hibernate之HQL查询
    Java设计模式----状态模式(State)
    Java设计模式----备忘录模式(Memento)
    Java设计模式----命令模式(Command)
    Java设计模式----责任链模式(Chain of Responsibility)
    Java基础小知识
    Hibernate检索策略
    Java设计模式----观察者模式(Observer)
    Google代码实验室
    Codeforces Round #257 (Div. 2) 前四题
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10425363.html
Copyright © 2011-2022 走看看