欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

牛客网暑期ACM多校训练营(第六场

程序员文章站 2022-04-02 18:51:50
...

F Squirtle
理解题意之后就十分好做了,唯一要注意的是会爆longlong,所以要用大数。
具体树dp见代码。

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

struct BigInt
{
    static const int BASE = 100000000;      //基数
    static const int WIDTH = 8;             //基宽
    vector<int> s;                          //存储

    //构造函数 -- 使用LL
    BigInt(long long num = 0)
    {
        *this = num;
    }

    //赋值运算符 -- 使用LL
    BigInt operator = (long long num)
    {
        s.clear();
        do
        {
            s.push_back(num % BASE);
            num /= BASE;
        }
        while(num > 0);
        return *this;
    }
    //赋值运算符 -- 使用string
    BigInt operator = (const string& str)
    {
        s.clear();
        int x, len = (str.length() - 1) / WIDTH + 1;
        for(int i = 0; i < len; i++)
        {
            int end = str.length() - i*WIDTH;
            int start = max(0, end - WIDTH);
            sscanf(str.substr(start, end-start).c_str(), "%d", &x);
            s.push_back(x);
        }
        return *this;
    }

    //比较运算符
    bool operator < (const BigInt& b) const
    {
        if(s.size() != b.s.size()) return s.size() < b.s.size();
        for(int i = s.size()-1; i >= 0; i--)
            if(s[i] != b.s[i]) return s[i] < b.s[i];
        return false; //相等
    }
    bool operator >  (const BigInt& b) const
    {
        return b < *this;
    }
    bool operator <= (const BigInt& b) const
    {
        return !(b < *this);
    }
    bool operator >= (const BigInt& b) const
    {
        return !(*this < b);
    }
    bool operator != (const BigInt& b) const
    {
        return b < *this || *this < b;
    }
    bool operator == (const BigInt& b) const
    {
        return !(b < *this) && !(*this < b);
    }

    //重载输入输出
    friend ostream& operator << (ostream &out, const BigInt& x)
    {
        out << x.s.back();
        for(int i = x.s.size()-2; i >= 0; i--)
        {
            char buf[20];
            sprintf(buf, "%08d", x.s[i]);
            for(int j = 0; j < strlen(buf); j++) out << buf[j];
        }
        return out;
    }
    friend istream& operator >> (istream &in, BigInt& x)
    {
        string s;
        if(!(in >> s)) return in;
        x = s;
        return in;
    }

    //加法
    BigInt operator + (const BigInt& b) const
    {
        BigInt c;
        c.s.clear();
        for(int i = 0, g = 0; ; i++)
        {
            if(g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = g;
            if(i < s.size())    x += s[i];
            if(i < b.s.size())  x += b.s[i];
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c;
    }

    //加等于
    BigInt operator += (const BigInt& b)
    {
        *this = *this + b;
        return *this;
    }



//减法 -- 大减小 -- 其他的在外部处理
    BigInt operator - (const BigInt& b) const
    {
        BigInt c;
        c.s.clear();
        if((*this) == b) return c = 0;
        for(int i = 0, g = 0; ; ++i)
        {
            if(g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = -g;
            g = 0;
            if(i < s.size())    x += s[i];
            if(i < b.s.size())  x -= b.s[i];
            if(x < 0) x += BASE, ++g;
            c.s.push_back(x);
        }
        for(int i = c.s.size()-1; i >= 0 && c.s[i] == 0; --i) c.s.pop_back();
        return c;
    }


    //乘法 -- 未使用FFT
    BigInt operator * (const BigInt& b) const
    {
        int s1 = s.size(), s2 = b.s.size();
        vector<LL> v(s1+s2+1,0);
        BigInt c;
        c.s.resize(s1+s2, 0);
        for(int i = 0; i < s1; ++i)        //相乘
            for(int j = 0; j < s2; ++j)
            {
                v[i+j] += (LL)s[i]*b.s[j];
            }
        for(int i = 0; i < s1+s2; ++i)      //进位
        {
            v[i+1] += v[i]/BASE;
            v[i] %= BASE;
            c.s[i] = v[i];
        }
        for(int i = c.s.size()-1; i >= 0 && c.s[i] == 0; --i) c.s.pop_back();
        return c;
    }

    //除法 -- 二分
    BigInt operator / (const BigInt& b) const
    {
        int s1 = s.size(), s2 = b.s.size();
        int len = s1-s2;
        BigInt c, x = *this, y = b;
        if(len < 0) return c = 0;

        c.s.resize(len+1, 0);
        for(int i = len; i >= 0; --i)
        {
            //先将除数对齐
            y.s.resize(s2+i,0);
            for(int j = s2+i-1; j >= 0; --j)
            {
                if(j >= i) y.s[j] = b.s[j-i];
                else y.s[j] = 0;
            }
            //再二分找商
            int L = 0, R = BASE;
            BigInt t;
            while(L < R)
            {
                int mid = (L+R)>>1;
                t = mid;
                if(t*y > x) R = mid;
                else L = mid+1;
            }
            c.s[i] = L-1;
            //更新被除数
            t = L-1;
            x = x - t*y;
        }
        for(int i = c.s.size()-1; i >= 0 && c.s[i] == 0; --i) c.s.pop_back();
        return c;
    }

    //取模
    BigInt operator % (const BigInt& b) const
    {
        return (*this) - (*this)/b * b;
    }

    //开方 -- 二分 -- 浮点数可放大1e4精确一位
    BigInt Sqrt()
    {
        BigInt L = 1, R = *this;
        while(L < R)
        {
            BigInt mid = (L+R)/2;
            if(mid*mid > *this) R = mid;
            else L = mid+1;
        }
        return L-1;
    }

};
const int maxn=2005;
vector<int>V[2*maxn+100];
char s[maxn][20];
BigInt dp[2*maxn+100][3];
BigInt tab[maxn];
int sze[2*maxn+100];
void dfs(int u)
{
    sze[u]=V[u].empty();
    if(V[u].empty())
    {
        dp[u][0]=dp[u][1]=1;
        return;
    }
    dfs(V[u][0]);
    sze[u]+=sze[V[u][0]];
    dfs(V[u][1]);
    sze[u]+=sze[V[u][1]];
    BigInt x[2],y[2];
    for(int j=0; j<2; j++)
    {
        if(j==0)
        {
            x[0]=dp[V[u][0]][0];
            x[1]=tab[sze[V[u][0]]]-x[0];
        }
        else
        {
            x[1]=dp[V[u][0]][1];
            x[0]=tab[sze[V[u][0]]]-x[1];
        }
        for(int k=0; k<2; k++)
        {
            if(k==0)
            {
                y[0]=dp[V[u][1]][0];
                y[1]=tab[sze[V[u][1]]]-y[0];
            }
            else
            {
                y[1]=dp[V[u][1]][1];
                y[0]=tab[sze[V[u][1]]]-y[1];
            }

            BigInt res[5];
            for(int t=0; t<4; t++)
                res[t]=x[(t>>1)&1]*y[t&1];
            for(int i=0; i<16; i++)if(s[u][i]=='1')
                {
                    BigInt tmp[2];
                    tmp[0]=tmp[1]=0;
                    for(int t=0; t<4; t++)
                    {
                        auto &thenum=tmp[(i>>t)&1];
                        thenum=thenum+res[t];
                    }

                    for(int t=0; t<2; t++)
                    {
                        if(dp[u][t]<tmp[t])
                            dp[u][t]=tmp[t];
                    }
                }
        }
    }
}
void init()
{
    tab[0]=1;
    for(int i=1; i<maxn; i++)
        tab[i]=tab[i-1]+tab[i-1];
}
int main()
{
    init();
    int T;
    scanf("%d",&T);
    int cas=1;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1; i<=n-1; i++)
            scanf("%s",s[i]);
        for(int i=1; i<=2*n-1; i++)V[i].clear(),dp[i][0]=dp[i][1]=0;

        int fa;
        for(int i=2; i<=2*n-1; i++)
        {
            scanf("%d",&fa);
            V[fa].push_back(i);
        }
        printf("Case #%d: ",cas++);
        dfs(1);
        cout<<dp[1][1]<<endl;
    }
    return 0;
}

G Pikachu
思路参考自小机灵鬼葫芦娃。
NJU-calabash_boy 2018/8/5 22:57:16
就是你考虑最大流等于最小割对吧
大学要有梦想 2018/8/5 22:57:19
dei
NJU-calabash_boy 2018/8/5 22:57:26
然后起点是u
NJU-calabash_boy 2018/8/5 22:57:32
终点是v
大学要有梦想 2018/8/5 22:57:47
恩。。
NJU-calabash_boy 2018/8/5 22:57:51
你猜一个可能是最小割的东西……
NJU-calabash_boy 2018/8/5 22:58:03
比如你把u出来的所有边割掉
NJU-calabash_boy 2018/8/5 22:58:16
或者把v出来的所有边删掉
NJU-calabash_boy 2018/8/5 22:58:22
然后取一个小的
NJU-calabash_boy 2018/8/5 22:58:35
然后你发现样例还真tmd对了
大学要有梦想 2018/8/5 22:58:39
。。。
2018/8/5 22:58:46
NJU-calabash_boy 2018/8/5 22:58:46
然后你就是要求题解说的那个东西了
NJU-calabash_boy 2018/8/5 22:58:57
最后注意爆掉了ll
NJU-calabash_boy 2018/8/5 22:59:30
这题他既然可以做………
NJU-calabash_boy 2018/8/5 22:59:38
这个最小割一定是有结论的
NJU-calabash_boy 2018/8/5 22:59:49
要不他一脸复杂度爆炸的样子
大学要有梦想 2018/8/5 22:59:55
哈哈。。
大学要有梦想 2018/8/5 23:00:00
谢谢葫芦娃
大学要有梦想 2018/8/5 23:00:06
你怎么这么聪明?
我竟无言以对。。
所以最后就是求一个点到所有的点的距离和就行了。这个过程树dp就能完成。
最后也会爆longlong,但爆的不是很多,所以这里有个处理技巧可以将一个数拆成两个数。
细节见代码。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
typedef pair<int,int>pii;
const int maxn=1e5+5;
vector<pii>G[maxn];
ll sum[maxn];
int sz[maxn];
void dfs1(int u,int pre)
{
    sz[u]=1;
    for(pii x:G[u])
    {
        int v=x.first,w=x.second;
        if(v==pre)continue;
        dfs1(v,u);
        sz[u]+=sz[v];
        sum[u]+=sum[v]+(ll)sz[v]*w;
    }
}
int n;
void dfs2(int u,int pre)
{
    for(pii x:G[u])
    {
        int v=x.first,w=x.second;
        if(v==pre)continue;
        ll tmp=sum[u]-sum[v]-(ll)sz[v]*w;
        sum[v]=sum[v]+tmp+(ll)(n-sz[v])*w;
        dfs2(v,u);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    int cas=1;
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)G[i].clear();
        int u,v,w;
        for(int i=1;i<n;i++)
        {
            sum[i]=0;
            scanf("%d %d %d",&u,&v,&w);
            G[u].push_back(make_pair(v,w));
            G[v].push_back(make_pair(u,w));
        }
        sum[n]=0;
        dfs1(1,0);
        dfs2(1,0);
        sort(sum+1,sum+1+n);
        ll ans1=0,ans2=0;
        for(int i=1;i<=n;i++)
        {
            ans1=ans1+sum[i]*(n-i);
            if(ans1>=(ll)1000000000000000000)
            {
                ans2+=ans1/1000000000000000000;
                ans1%=1000000000000000000;
            }
        }
        if(ans2==0)
            printf("Case #%d: %llu\n",cas++,ans1);
        else printf("Case #%d: %llu%llu\n",cas++,ans2,ans1);
    }
    return 0;
}

I Team Rocket
这题博主没有用题解的方法,自己写的比较暴力,你可以开2e5个set,对于每个set的下标对应的是每个区间的左坐标,然后将右坐标依从大到小的顺序放进set里,然后每次询问的时候跑就行了,如果一个set被全部删后,以后跑就不用跑这个了,那么你可以用并查集来稍微优化一下。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const int mod=998244353;
set<pair<int,int>,greater<pair<int,int> >>S[maxn];
typedef pair<int,int>pii;
pii lines[maxn];
int L[maxn];
int f[maxn];
inline int find(int a)
{
    return a==f[a]?a:f[a]=find(f[a]);
}
int vis[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    int cas=1;
    while(T--)
    {
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)vis[i]=0;
        int l,r;
        for(int i=1;i<=n;i++)
        {
            S[i].clear();
            scanf("%d %d",&l,&r);
            lines[i]=pii(l,r);
            L[i]=l;
        }
        sort(L+1,L+1+n);
        int lnum=unique(L+1,L+1+n)-L-1;
        for(int i=1;i<=n;i++)
        {
            int idx=lower_bound(L+1,L+1+lnum,lines[i].first)-L;
            S[idx].insert(pii(lines[i].second,i));
        }
        for(int i=1;i<=lnum+1;i++)f[i]=i;
        int last=0;
        printf("Case #%d:\n",cas++);
        for(int t=1;t<=m;t++)
        {
            int y;
            scanf("%d",&y);
            int x=(y^last);
            int idx=upper_bound(L+1,L+1+lnum,x)-L;

            int begin=find(1);
            long long tmp=1;
            int flag=0;
            for(int i=begin;i<idx;i=find(i+1))
            {
                auto it=S[i].begin();
                for(;it!=S[i].end();)
                {
                    if((it->first)>=x)
                    {
                        vis[it->second]=t;
                        tmp=tmp*(it->second)%mod;
                        flag++;
                        S[i].erase(it++);
                    }
                    else break;
                }
                if(it==S[i].end())
                {
                    int fv=find(i+1);
                    f[i]=fv;
                }
            }
            if(flag==0)
                last=0;
            else last=tmp;
            printf("%d\n",flag);
        }
        for(int i=1;i<=n;i++)
        {
            if(i!=1)printf(" ");
            printf("%d",vis[i]);
        }
        puts("");
    }
    return 0;



}

J Heritage of skywalkert
这题又气死我了,全场都会就我不会。。
细节看题解就完事了。

#include<bits/stdc++.h>
using namespace std;
unsigned x,y,z;
const int maxn=1e7+5;
unsigned a[maxn];
unsigned tang()
{
    unsigned t;
    x^=x<<16;
    x^=x>>5;
    x^=x<<1;
    t=x;
    x=y;
    y=z;
    z=t^x^y;
    return z;
}
long long gcd(long long a,long long b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    int T;
    scanf("%d",&T);
    int cas=1;
    while(T--)
    {
        int n;
        cin>>n>>x>>y>>z;
        for(int i=1;i<=n;i++)
            a[i]=tang();
        int themin=min(200,n);
        nth_element(a+1,a+themin,a+1+n,greater<unsigned>());
        unsigned long long ans=0;
        for(int i=1;i<=themin;i++)
            for(int j=1;j<=themin;j++)
        {
            long long tmp=gcd(a[i],a[j]);
            ans=max(ans,(unsigned long long)a[i]*a[j]/tmp);
        }
        printf("Case #%d: %llu\n",cas++,ans);
    }
    return 0;



}
相关标签: 牛客 多校