• 2018.7.15模拟考试


    emmm...作为本蒟蒻的实际意义上的第一篇博客,当然要认真写写才不反正也没什么人看

    T1 题意简述:求二元不定方程的正整数解组数。

           T≤10000,-1,000,000≤a,b,c≤1,000,000
       解题思路:扩展欧几里得即可,关于负数可以特判。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    using namespace std;
    ll T;
    ll gcd(ll x,ll y)
    {
        while(x%y!=0)
        {ll tmp=y;y=x%y;x=tmp;}
        return y;
    }
    ll spj(ll &x,ll &y,ll &z) 
    {
        if(!x&&!y&&!z) {printf("ZenMeZheMeDuo
    ");return 1;}
        if(!x&&!y&&z) {printf("0
    ");return 1;}
        if(!y) swap(x,y);
        if(!x&&y&&!z) {printf("0
    ");return 1;}
        if(!x&&y&&z)
        {
            if((y<0&&z>0)||(y>0&&z<0)) {printf("0
    ");return 1;}
            if(z%y!=0) {printf("0
    ");return 1;}
            if(x%y==0) {printf("ZenMeZheMeDuo
    ");return 1;}
        }
        if(x<0&&y<0&&z>=0) {printf("0
    ");return 1;}
        if(x<0&&y<0&&z<0) x=-x,y=-y,z=-z;
        return 0;
    }
    void exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(!b)
        {
            x=1;y=0;
            return;
        }
        exgcd(b,a%b,y,x);
        y=y-a/b*x;
    }
    int main()
    {
        freopen("fuction.in","r",stdin);
        freopen("fuction.out","w",stdout);
        scanf("%lld",&T);
        while(T--)
        {
            ll u,v,w;
            scanf("%lld%lld%lld",&u,&v,&w);
            if(spj(u,v,w)) continue;
            ll tmp=gcd(u,v);
            if(w%tmp!=0) {printf("0
    ");continue;}
            if((u<0&&v>0)||(u>0&&v<0)) {printf("ZenMeZheMeDuo
    ");continue;}
            u=u/tmp;v=v/tmp;w=w/tmp;
            ll x,y;
            exgcd(u,v,x,y);
            x*=w,y*=w;
            if(x>0&&y<=0) swap(x,y),swap(u,v);
            if(x<=0)
            {
                ll xx=x;
                x+=((0-xx)/v+1)*v;
                y-=((0-xx)/v+1)*u;
            }
            if(x<=0||y<=0) {printf("0
    ");continue;}
            ll ans=0;
            ans=y/u+(y%u>0);
            if(ans>65535) {printf("ZenMeZheMeDuo
    ");continue;}
            printf("%lld
    ",ans);
        }
        return 0;
    }
     

     
    T2 题意简述:有一棵点数为n的树,树边有边权。将m个点染成黑色,并将其他的点染成白色。会获得
                 黑点两两之间的距离和加上白点两两之间的距离和的收益。问收益最大值是多少。
                 0≤m≤n≤2000,1≤c≤1,000,000
       解题思路:考虑(u,v)这条边的贡献,发现在这条边两边的子树上的黑点都可以两两配对,白点
                 亦然。因此贡献为
           ( Black(u)* Black(v)+ White(u)* White(v))* val(u,v)
           发现可以用树形DP递推至根节点,在计算贡献时用一个背包即可。
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    using namespace std;
    ll n,blk,cnt,head[2001],siz[2001],dp[2001][2001];
    struct uio{
        ll nxt,to,val;
    }edge[4001];
    void add(ll x,ll y,ll z)
    {
        edge[++cnt].nxt=head[x];
        edge[cnt].to=y;
        edge[cnt].val=z;
        head[x]=cnt;
    }
    void dfs(ll x,ll fa)
    {
        siz[x]=1;
        dp[x][0]=dp[x][1]=0;
        for(ll i=head[x];i;i=edge[i].nxt)
        {
            ll y=edge[i].to;
            if(y==fa) continue;
            dfs(y,x);
            siz[x]+=siz[y];
        }
        for(ll i=head[x];i;i=edge[i].nxt)
        {
            ll y=edge[i].to,z=edge[i].val;
            if(y==fa) continue;
            for(ll j=min(siz[x],blk);j>=0;j--)
                for(ll k=0;k<=min(j,siz[y]);k++)
                    if(dp[x][j-k]!=-1)
                    {
                        ll wei=z*(k/*此子树黑点个数*/*(blk-k)/*另一子树黑点个数*/+
                                (siz[y]-k)/*此子树白点个数*/*(n-blk-(siz[y]-k))/*另一子树白点个数*/);
                        dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[y][k]+wei);
                    }
        }
    }
    int main()
    {
        freopen("coloration.in","r",stdin);
        freopen("coloration.out","w",stdout);
        scanf("%lld%lld",&n,&blk);
        for(ll i=1;i<n;i++)
        {
            ll u,v,w;
            scanf("%lld%lld%lld",&u,&v,&w);
            add(u,v,w),add(v,u,w);
        }
        memset(dp,-1,sizeof(dp));
        dfs(1,0);
        printf("%lld
    ",dp[1][blk]);
        return 0;
    }
     

     
    T3 题意简述:

          n,m,k≤100000

     

       解题思路:首先感谢坐在我旁边的ErkkiErkko大佬教会我这道题。ErkkiErkko大佬TQL!!!

                 容易看出,光线改变方向的次数是O(n+m+k)级别的,因此我们可以进行模拟。

                 把障碍存在set里(边界也要存),每次由光线所在位置及朝向方向+lower_bound即可得

                 出下一障碍位置。

                 时间复杂度O((n+m+k)logn )。

                 由于光线不会相交在块内 <=== ErkkiErkko大佬证明得出

                 因此不必去重,且结束条件仅两种:

                 1.光线回到起点,且路径上的每个点都只经过一次

                 2.光线回到起点,且路径上的每个点都经过了两次

                 对于这两种情况,只需记录是否曾沿反方向经过了起点,若是则将ans/2,否则直接输出

                 ans即可。

       代码:尚未码出,稍后补足。(咕咕咕?

  • 相关阅读:
    mongodb分布式查询
    MongoDB JAVA API Filters
    mongodb.conf配置文件详解
    mongodb安装配置
    Elasticsearch-2.3.x填坑之路
    C++对象模型详解
    关于虚函数的那些事儿
    关于B树的一些总结
    动态规划问题
    C中的qsort函数和C++中的sort函数的理解与使用
  • 原文地址:https://www.cnblogs.com/water-radish/p/9315121.html
Copyright © 2020-2023  润新知