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

版权声明:转载之前请说你是博主的粉丝哦。 https://blog.csdn.net/qq_34921856/article/details/81454692

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;



}

猜你喜欢

转载自blog.csdn.net/qq_34921856/article/details/81454692
今日推荐