• 集训队日常训练20180518-DIV1


    A.3583

    n根木棍是否能分成相等两堆。

    背包dp,首先求和sum,如果为偶数就说明不行,否则考虑做一个sum/2大小的背包。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int n,w[105];
     7     while(scanf("%d",&n)!=EOF)
     8     {
     9         int sum=0;
    10         for(int i=1;i<=n;i++)scanf("%d",&w[i]),sum+=w[i];
    11         bool dp[10005];
    12         memset(dp,0,sizeof dp);
    13         dp[0]=1;
    14         for(int i=1;i<=n;i++)
    15             for(int j=sum/2;j>=w[i];j--)
    16                 dp[j]=dp[j]|dp[j-w[i]];
    17         printf("%s
    ",dp[sum/2]&&sum%2==0?"Yes":"No");
    18     }
    19     return 0;
    20 }
    A.cpp

    B.5146

    单身狗在[l,r]之间且二进制中1的数量最多的数,若有多个输出最小的。

    贪心,可以发现想要二进制最多,那么一定从最低位开始。

    那么想要在[l,r]之间,先把l变成二进制,贪心即可(想想为什么)。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll __int64
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int a[105]={0},p=0;
            ll l,r,ans;
            scanf("%I64d%I64d",&l,&r);
            ans=l;
            while(l)
            {
                a[p++]=l&1;
                l>>=1;
            }
            for(int i=0;i<=60;i++)
            {
                if(a[i]==0&&ans+(1LL<<i)<=r)
                {
                    ans+=1LL<<i;
                    a[i]=1;
                }
            }
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    B.cpp

    C.3153

    n个点m条无向边,问必须经过S<=10个点再回到起点0的最短路。

    dijstra+状压dp,考虑对每个S跑一边dijstra,求出S到每个点的最短路。

    dp[i][j]代表状态为i,现在在j点的最短路。

    #include <bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    const int N=100005;
    vector<pair<int,int> > G[N];
    ll d[10][N],dp[1<<10][10];
    int a[10],T,n,m;
    void dij(int p,int u)
    {
        for(int i=0;i<n;i++)
            d[p][i]=1LL<<60;
        d[p][u]=0;
        queue<int> qu;
        qu.push(u);
        while(!qu.empty())
        {
            int x=qu.front();
            qu.pop();
            for(int i=0;i<G[x].size();i++)
            {
                int v=G[x][i].first,c=G[x][i].second;
                if(d[p][v]>d[p][x]+c) d[p][v]=d[p][x]+c,qu.push(v);
            }
        }
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=0;i<n;i++) G[i].clear();
            for(int i=0,u,v,c;i<m;i++)
            {
                scanf("%d%d%d",&u,&v,&c);
                G[u].push_back({v,c});
                G[v].push_back({u,c});
            }
            scanf("%d",&m);
            int S=1<<m;
            for(int i=0;i<m;i++) scanf("%d",&a[i]),dij(i,a[i]);
            for(int i=0;i<S;i++)
                for(int j=0;j<m;j++)
                    dp[i][j]=1LL<<60;
            for(int i=0;i<m;i++)
                dp[1<<i][i]=d[i][0];
            for(int s=1;s<S;s++)
            {
                for(int i=0;i<m;i++)
                    if((1<<i)&s)
                    {
                        for(int j=0;j<m;j++)
                            if(((1<<j)&s)==0)
                                dp[s|(1<<j)][j]=min(dp[s|(1<<j)][j],dp[s][i]+d[i][a[j]]);
                    }
            }
            ll ans=1LL<<60;
            for(int i=0;i<m;i++)
                ans=min(ans,dp[S-1][i]+d[i][0]);
            printf("%I64d
    ",ans);
        }
        return 0;
    }
    C.cpp

    D.3176

    n<=30个值,每个值(0,2^16),求最小需要几个数的异或后值为0,每个数只能取1次。

    背包dp,考虑dp[i]代表异或值为i的最少个数。

    #include<bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        int n,x,dp[1<<16];
        memset(dp,0x3f3f3f3f,sizeof dp);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            for(int j=(1<<16)-1;j>=0;j--)
                dp[j^x]=min(dp[j^x],dp[j]+1);
            dp[x]=1;
        }
        if(dp[0]==0x3f3f3f3f)printf("-1");
        else printf("%d",dp[0]);
    }
    D.cpp

    E.3166

    给一堆等级,和每个等级的区间,然后n个初始得分,每小时加1分,每个查询输出D小时后达到等级L的人数。

    二分,从小到大排序,那么就是有多少个数ai+D在等级L的区间内,就相当于区间-D,然后二分左右段点。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+5;
    int a[N],n,q,d,l,L,R;
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d",&d,&l);
            if(l==1)L=0,R=100;
            if(l==2)L=101,R=500;
            if(l==3)L=501,R=2000;
            if(l==4)L=2001,R=10000;
            if(l==5)L=10001,R=50000;
            if(l==6)L=50001,R=200000;
            if(l==7)L=200001,R=2e9+7;
            int x1=lower_bound(a+1,a+1+n,L-d)-a;
            int x2=upper_bound(a+1,a+1+n,R-d)-a;
            printf("%d
    ",x2-x1);
        }
        return 0;
    }
    E.cpp

    F.2704

    n个点m条无向边边权为1,从1出发问距离最远的点,如有多个输出编号最小的点,再输出距离,再输出有几个点。

    dijstra模板题。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=2e4+5;
    vector<int>G[N];
    int n,m,u,v;
    void bfs()
    {
        int d[N];
        memset(d,0x3f3f3f3f,sizeof d);
        queue<int>q;
        d[1]=0;
        q.push(1);
        while(!q.empty())
        {
            int u=q.front();q.pop();
            for(int i=0;i<G[u].size();i++)
            {
                int v=G[u][i];
                if(d[v]>d[u]+1)
                {
                    d[v]=d[u]+1;
                    q.push(v);
                }
            }
        }
        int maxx=-1,posi=0,ans=0;
        for(int i=1;i<=n;i++)
            if(d[i]>maxx)maxx=d[i],posi=i;
        for(int i=1;i<=n;i++)
            if(d[i]==maxx)ans++;
        cout<<posi<<" "<<maxx<<" "<<ans;
    }
    int main()
    {
        cin>>n>>m;
        for(int i=0;i<m;i++)
        {
            cin>>u>>v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        bfs();
        return 0;
    }
    F.cpp

    G.3168

    n瓶奶生产商和生产日期保证2008年,m个生产商对应奶的保质期,给你一个开始的日期,每天最多喝一瓶,问最少几瓶会过期。

    哈希+贪心,把每个日期转化成天,优先处理过期时间最早的。

    #include<bits/stdc++.h>
    using namespace std;
    int a[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
    vector<int>v[100];
    int b[600];
    int main()
    {
        std::ios::sync_with_stdio(false); 
        map<string,int>m;
        int id=1,n,x,y;
        char ch;
        string s;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>s;
              if(m[s]==0)
                m[s]=id++;
              cin>>x>>ch>>y;
              int day=0;
              for(int j=1;j<x;j++)
                day+=a[j];
            day+=y;
            v[m[s]].push_back(day);
        }
        int t;
        cin>>t;
        for(int i=1;i<=t;i++)
        {
            cin>>s>>x;
            for(int j=0;j<v[m[s]].size();j++)
                b[v[m[s]][j]+x]++;
        }
        cin>>x>>ch>>y;
        int day=0;
        for(int j=1;j<x;j++)
            day+=a[j];
        day+=y;
        int sum=0;
        for(int i=1;i<=day;i++)
            sum=sum+b[i];
        int p=day;
        for(int i=day+1;i<600;i++)
        {
            while(b[i]>0)
            {
                if(p<i)
                    p++,b[i]--;
                else
                {
                    sum+=b[i];
                    break;
                }
            }
        }
        cout<<sum<<endl;
        return 0;
    }
    G.cpp

    H.3213

    n<=8个题目选择k个难度总和<=p求方案数。

    n很小,直接暴力dfs。

    #include <bits/stdc++.h>
    using namespace std;
    int v[10],n,k,p,ans;
    void DFS(int pos,int s,int cnt)
    {
        if(s <= p && cnt == k) {ans++;return;}
        if(cnt > k || s > p) return;
        for(int i = pos; i < n; i++)
        {
            DFS(i + 1,s + v[i],cnt + 1);
        }
    }
    int main()
    {
        int t; scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d%d",&n,&k,&p);
            for(int i = 0; i < n; i++) scanf("%d",&v[i]);
            ans = 0;
            DFS(0,0,0);
            printf("%d
    ",ans);
        }
        return 0;
    }
    H.cpp

    I.5069

    给n*m的图,求一个四周全是‘.’的最大矩形。

    思维,a为列前缀和,b为行前缀和,(i,j)---(i,k)那么第i行的a[i][k]-a[i][j]==k-j那么第i行j->k都是1,x=min(b[i][j],b[i][k])代表j向上或者k向上连续1的数量,然后只需要判断a[i-x+1][k]-a[i-x+1][j]==k-j,这就说明第i-x+1行j­->k都是1,复杂度O(n^3)。

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m;
    char G[205][205];
    int a[205][205],b[205][205];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%s",G[i]+1);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(G[i][j]=='.')
                    a[i][j]=a[i][j-1]+1,
                    b[i][j]=b[i-1][j]+1;
                else
                    a[i][j]=0,
                    b[i][j]=0;
        //(i,j)     (i,k)
        int maxx=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                for(int k=j;k<=m;k++)
                {
                    if(a[i][k]-a[i][j]!=k-j)break;
                    if(b[i][j]&&b[i][k])
                    {
                        int x=min(b[i][j],b[i][k]);
                        while(a[i-x+1][k]-a[i-x+1][j]!=k-j)x--;
                        maxx=max(maxx,x*(k-j+1));
                    }
                }
            }
        printf("%d",maxx);
        return 0;
    }
    I.cpp

    J.4482

    n个数的积为A,m个数的积为B,求A和B的gcd。

    zdragon的O((n+m)*sqrt(1e9))

    求A的所有素因子,求B的所有素因子,枚举所有素因子,答案就是素因子^(该素因子A有几个,该素因子B有几个)的积。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1005;
    const int MD=1000000000;
    int a[N<<2],b[N<<2],cnt;
    bool f;
    map<int,int> ma,mma;
    long long quick_pow(long long x,int y)
    {
        long long ans=1;
        while(y)
        {
            if(y&1)
            {
                ans*=x;
                if(ans>MD||f) ans%=MD,f=true;
            }
            x*=x;
            if(x>MD||f) x%=MD,f=true;
            y>>=1;
        }
        return ans;
    }
    int main()
    {
        int n,m;
        scanf("%d",&n);
        for(int i=0,x;i<n;i++)
        {
            scanf("%d",&x);
            for(int j=2;1LL*j*j<=x;j++)
            {
                if(x%j==0)
                {
                    if(!ma[j]) ma[j]=(++cnt),mma[cnt]=j;
                    while(x%j==0) a[ma[j]]++,x/=j;
                }
            }
            if(x>1)
            {
                if(!ma[x]) ma[x]=(++cnt),mma[cnt]=x;
                a[ma[x]]++;
            }
        }
        scanf("%d",&m);
        for(int i=0,x;i<m;i++)
        {
            scanf("%d",&x);
            for(int j=2;1LL*j*j<=x;j++)
            {
                if(x%j==0)
                {
                    if(!ma[j]) ma[j]=(++cnt),mma[cnt]=j;
                    while(x%j==0) b[ma[j]]++,x/=j;
                }
            }
            if(x>1)
            {
                if(!ma[x]) ma[x]=(++cnt),mma[cnt]=x;
                b[ma[x]]++;
            }
        }
        long long ans=1;
        for(int i=1;i<=cnt;i++)
        {
            ans=ans*quick_pow(1LL*mma[i],min(a[i],b[i]));
            if(ans>MD||f) ans%=MD,f=true;
        }
        if(f) printf("%09I64d
    ",ans);
        else printf("%I64d
    ",ans);
        return 0;
    }
    J.cpp O((n+m)*sqrt(1e9))

    wff的O(n*m)

    暴力gcd。

    #include <bits/stdc++.h>
    using namespace std;
    const int inf =0x3f3f3f3f;
    #define ll long long
    
    int a[1005],b[1005];
    int main()
    {
        ll ans1=1,ans2=0;
        int n,m;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            scanf("%d",&b[i]);
        }
        int flag=0;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                int t=__gcd(a[i],b[j]);
                ans1=1ll *ans1 * t ;
                if(!flag&&ans1>= 1000000000) flag=1;
                ans1%=1000000000;
                a[i]/=t;
                b[j]/=t;
            }
        }
        if(flag) printf("%09I64d",ans1% 1000000000);
        else printf("%I64d",ans1% 1000000000);
        return 0;
    }
    J.cpp O(n*m)

    K.4426

    n个人初始分ai,第一名+n分,第二名+n-1分,以此类推,如果一个人i是冠军那么他的得分大于等于其他所有人的得分,问有几个人可能是冠军。

    贪心,首先按ai从小到大排序,得分最高的加1分,第二高加2分,以此类推,maxx=ai+n-i+1的最大值,如果一个人i是冠军,那么ai+n大于等于maxx。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=3e5+5;
    int a[N],n,ans,sum;
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        for(int i=n;i>=1;i--)ans=max(ans,a[i]+n-i+1);
        for(int i=1;i<=n;i++)if(a[i]+n>=ans)sum++;
        printf("%d",sum);
        return 0;
    }
    K.cpp

    L.3457

    给一个整数,输出重排列后的最小值。

    贪心,首先第一个数不能为0,那么先取个不是0的最小放在第一个。然后按小到大输出。

    #include<stdio.h>
    #include<string.h>
    int main()
    {
        int i,j;
        char a[30];
        while(scanf("%s",&a)!=EOF)
        {
            int b[10]={0},min=10;
            for(i=0;i<strlen(a);i++)
            {
                b[a[i]-'0']++;
                if(a[i]-'0'<min&&a[i]-'0'!=0)
                min=a[i]-'0';
            }
            printf("%d",min);
            b[min]--;
            for(i=0;i<10;i++)
            {
                for(j=0;j<b[i];j++)
                printf("%d",i);
            }
            printf("
    ");
        }
        return 0;
    }
    L.cpp

    M.2609

    n个点m条无向边最多k次操作使得边花费为0,求1到n的最短路。

    堆优化的dijstra+dp,分成k层,dp[k][i]表示已经让k条边花费变成0到i的最短路。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=1e4+5;
    const int maxm=5e4+5;
    const int maxk=20+5;
    
    inline int read() {
       int x=0,f=1;char c=getchar();
       for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
       for(;'0'<=c&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
       return x*f;
    }
    
    vector< pair<int,int> >G[maxn];
    int d[maxk][maxn],vis[maxk][maxn];
    int n,m,k;
    struct edge
    {
        int v,k,w;
        bool operator<(const edge& D)const{
            return w>D.w; 
        }
    };
    int dij()
    {
        for(int i=0;i<=k;i++)for(int j=0;j<=n;j++)d[i][j]=0x3f3f3f3f,vis[i][j]=0;
        priority_queue<edge>q;
        q.push({1,0,0});
        d[0][1]=0;
        while(!q.empty())
        {
            edge u=q.top();q.pop();
            //printf("%d %d
    ",u.v,u.w);
            if(u.v==n)return u.w;
            if(vis[u.k][u.v])continue;
            vis[u.k][u.v]=1;
            for(auto x:G[u.v])
            {
                int v=x.first;
                int w=x.second;
                if(d[u.k][v]>u.w+w)
                    q.push({v,u.k,d[u.k][v]=u.w+w});
                if(u.k<k&&d[u.k+1][v]>u.w)
                    q.push({v,u.k+1,d[u.k+1][v]=u.w});
            }
        }
        return 0x3f3f3f3f;
    }
    int main()
    {
        n=read(),m=read(),k=read();
        for(int i=1,u,v,w;i<=m;i++)
        {
            u=read(),v=read(),w=read();
            G[u].push_back({v,w});
            G[v].push_back({u,w});
        }
        printf("%d
    ",dij());
        return 0;
    }
    M.cpp
  • 相关阅读:
    动手学习TCP:TCP连接建立与终止
    动手学习TCP: 环境搭建
    Python 数据分析4
    Django unittest 单元测试
    Django commands自定制
    Python mac安装mysqlclient的一个bug
    Centos7 开机启动流程
    Centos 06 文件类型和扩展名&索引节点inode和存储块block
    Centos 05 系统目录讲解
    Linux 踩过的坑系列-01
  • 原文地址:https://www.cnblogs.com/taozi1115402474/p/10884255.html
Copyright © 2020-2023  润新知