• 集训队日常训练20180513-DIV1


    A.3132

    给一个有向图,问能否从任意点出发都能进入一个环中。

    深搜。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=55;
    vector<int>G[N];
    bool vis[N];
    int f;
    void dfs(int u)
    {
        if(f)return;
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(!vis[v])
            {
                vis[v]=1;
                dfs(v);
            }
            else
            {
                f=1;
                return;
            }
        }
    }
    int main()
    {
        int n,m;
        char s1[5],s2[5];
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(int i=1;i<=n;i++)G[i].clear();
            for(int i=0;i<m;i++)
            {
                int u,v;
                scanf("%s%s",s1,s2);
                G[s1[0]-'A'+1].push_back(s2[0]-'A'+1);
            }
            for(int i=1;i<=n;i++)
            {
                f=0;
                memset(vis,0,sizeof vis);
                dfs(i);
                if(!f)break;
            }
            printf("%s
    ",f?"YES":"NO");
        }
        return 0;
    }
    A.cpp

    B.4971

    给一颗树,n个起点,问到1的路径权值和,一个点的权值只算一次。

    深搜。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1005;
    vector<int>G[N];
    bool vis[N];
    int father[N],be[N],val[N];
    void dfs(int u,int fa)
    {
        father[u]=fa;
        for(int i=0;i<G[u].size();i++)
        {
            int v=G[u][i];
            if(v==fa)continue;
            dfs(v,u);
        }
    }
    int main()
    {
        int n,m,ca=1;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(vis,0,sizeof vis);
            for(int i=1;i<=n;i++)G[i].clear();
            for(int i=1;i<=m;i++)
                scanf("%d",&be[i]);
            for(int i=1;i<=n;i++)
                scanf("%d",&val[i]);
            for(int i=1;i<n;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                G[u].push_back(v);
                G[v].push_back(u);
            }
            dfs(1,0);
            int sum=0;
            for(int i=1;i<=m;i++)
            {
                int f=be[i];
                if(!vis[f])vis[f]=1,sum+=val[f];
                while(f)
                {
                    f=father[f];
                    if(!vis[f])vis[f]=1,sum+=val[f];
                }
            }
            printf("Case #%d: %d
    ",ca++,sum);
        }
        return 0;
    }
    B.cpp

    C.4976

    给一个二进制串,其中有一堆未知数,问有几种填法使得十进制数中含6。

    深搜。

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    int p[1005];
    
    string s;
    int l;
    int num=0;
    void dfs(int pos,ll ans)
    {
        if(pos==l)
        {
            while(ans)
            {
                if(ans%10==6)
                {
                    num++;
                    break;
                }
                ans=ans/10;
            }
            return;
        }
        if(s[pos]=='0') dfs(pos+1,ans*2);
        else if(s[pos]=='1') dfs(pos+1,ans*2+1);
        else
        {
            dfs(pos+1,ans*2);
            dfs(pos+1,ans*2+1);
        }
    }
    int main()
    {
        while(cin>>s)
        {
           num=0;
           l=s.size();
           dfs(0,0);
           cout<<num<<endl;
        }
        return 0;
    }
    C.cpp

    D.4546

    M段区间每段区间只能有一张假票,问最多能有几张假票,若不合法输出-1。

    不会(待补)

    #include <iostream>
    #include <stdio.h>
    #include <vector>
    using namespace std;
    #define MAXN 200010
    
    int DP[MAXN];
    int RMN[MAXN];
    int RMX[MAXN];
    
    template <class T>
    struct max_queue
    {
        max_queue(size_t sz) : X(sz), Y(sz), a(0), b(0), va(0), vb(0)
        {}
        void push(const T& v)
        {
            while(va < vb && X[vb - 1] <= v)
                vb--;
            X[vb] = v;
            Y[vb++] = b++;
        }
    
        void pop()
        {
            va += a++ == Y[va];
        }
    
        T max()
        {
            return X[va];
        }
    
        vector<T> X;
        vector<size_t> Y;
        size_t a, b, va, vb;
    };
    
    int main() {
    //    freopen("d:\data1.in","r",stdin);
    //    freopen("d:\data1.out","w",stdout);
        int N, M; scanf("%d%d", &N, &M);
        fill(RMN, RMN + N + 1, N + 2);
        for(int i = 0; i < M; i++)
        {
            int lft, rht; scanf("%d%d", &lft, &rht);
            RMN[lft] = min(RMN[lft], rht + 1);
            RMX[lft] = max(RMX[lft], rht + 1);
        }
        RMN[N + 1] = N + 2;
        for(int i = N - 1; i >= 0; i--)
        {
            RMN[i] = min(RMN[i], RMN[i + 1]);
        }
        for(int i = 1; i <= N; i++)
        {
            RMX[i] = max(RMX[i], RMX[i - 1]);
        }
        DP[N + 1] = 0;
    
        int j_lo = N;
        int j_hi = N;
        max_queue<int> mq(N);
        for(int i = N; i >= 0; i--)
        {
            int r_least = max(i + 1, RMX[i]);
            int r_most = RMN[i + 1];
            for(; r_least <= j_lo; j_lo--)
            {
                mq.push(DP[j_lo]);
            }
            for(; j_lo < j_hi && r_most <= j_hi; j_hi--)
            {
                mq.pop();
            }
            DP[i] = r_least < r_most ? mq.max() : -1;
            if(i && DP[i] != -1)
            {
                DP[i]++;
            }
        }
    
        printf("%d
    ", DP[0]);
        return 0;
    }
    D.cpp by crq

    E.4587

    有两颗苹果树,贝西初始站在1下,每分钟掉下1个苹果,贝西最多移动W次,问T分钟贝西最多能接到多少苹果。

    dp[t][w][3]表示在t分钟移动w次现在站在苹果树几下。

    #include<bits/stdc++.h>
    using namespace std;
    int dp[1005][35][2];
    int main()
    {
        for(int i=0;i<1005;i++)
            for(int j=0;j<35;j++)
                dp[i][j][0]=dp[i][j][1]=-1000000000;
        int T,W;
        scanf("%d%d",&T,&W);
        for(int i=0;i<T;i++) dp[i][W][0]=0;
        for(int i=0,x;i<T;i++)
        {
            scanf("%d",&x);
            if(!i)
            {
                if(x==1) dp[i][W][0]=1;
                else if(x==2) dp[i][W-1][1]=1;
            }
            else
            {
                for(int j=W;j>=0;j--)
                {
                    if(x==1)
                    {
                        dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]+1);
                        if(j!=W) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j+1][1]+1);
                        dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]);
                        if(j!=W) dp[i][j][1]=max(dp[i][j][1],dp[i-1][j+1][0]);
                    }
                    else if(x==2)
                    {
                        dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]+1);
                        if(j!=W) dp[i][j][1]=max(dp[i][j][1],dp[i-1][j+1][0]+1);
                        dp[i][j][0]=max(dp[i][j][0],dp[i-1][j][0]);
                        if(j!=W) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j+1][1]);
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<=W;i++)
            ans=max(ans,max(dp[T-1][i][0],dp[T-1][i][1]));
        printf("%d
    ",ans);
        return 0;
    }
    E.cpp

    F.4596

    n个盒子按1-n编号,m次操作,1XY把x放在y左边,2XY把x放在y右边,3XYxy互换位置,4翻转,问操作完所有奇数位置的盒子编号之和。

    双向链表,L[i]=i-1,R[i]=i+1,然后4操作后1和2操作是反过来的,3操作的交换可能存在相邻两个,这时候要判断左右。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+5;
    int L[N],R[N];
    int main()
    {
        int n,m,o=0;
        while(~scanf("%d%d",&n,&m))
        {
            for(int i=0;i<=n+1;i++) L[i]=i-1,R[i]=i+1;
            int r=0;
            while(m--)
            {
                int op,x,y;
                scanf("%d",&op);
                if(op==4)r=!r;
                else
                {
                    scanf("%d%d",&x,&y);
                    if(op==3&&R[y]==x)swap(x,y);
                    if(op!=3&&r)op=3-op;
                    if(op==1)
                    {
                        if(x==L[y])continue;
                        R[L[x]]=R[x];
                        L[R[x]]=L[x];
                        L[x]=L[y];
                        R[x]=y;
                        R[L[y]]=x;
                        L[y]=x;
                    }
                    else if(op==2)
                    {
                        if(x==R[y])continue;
                        R[L[x]]=R[x];
                        L[R[x]]=L[x];
                        L[x]=y;
                        R[x]=R[y];
                        L[R[y]]=x;
                        R[y]=x;
                    }
                    else if(op==3)
                    {
                        if(R[x]==y||L[x]==y||R[y]==x||L[y]==x)
                        {
                            R[L[x]]=y;
                            L[R[y]]=x;
                            L[y]=L[x];
                            R[x]=R[y];
                            R[y]=x;
                            L[x]=y;
                        }
                        else
                        {
                            R[L[x]]=L[R[x]]=y;
                            R[L[y]]=L[R[y]]=x;
                            swap(L[x],L[y]);
                            swap(R[x],R[y]);
                        }
                    }
                }         
            }
            long long sum=0;
            for(int i=R[0];i<=n;i=R[R[i]]) sum+=i;
            if(r&&(n&1)==0) sum=1LL*n*(n+1)/2-sum;
            printf("Case %d: %I64d
    ",++o,sum);
        }
        return 0;
    }
    F.cpp

    G.5066

    n个点m条有向边,问从1出发最多经过几个点再回到1。

    targin求含有1的强连通集合。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=1e5+5;
    int low[N],dfn[N],Stack[N],tot,cnt;
    bool instack[N];
    vector<int>G[N];
    void tarjan(int u)
    {
        int v;
        dfn[u]=low[u]=++tot;
        Stack[++cnt]=u;
        instack[u]=true;
        for(int i=0;i<G[u].size();i++)
        {
            v=G[u][i];
            if(!dfn[v])
            {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(instack[v])
                low[u]=min(low[u],dfn[v]);
        }
        if(low[u]==dfn[u])
        {
            int sz=0;
            while(v=Stack[cnt--])
            {
                instack[v]=false;
                sz++;
                if(u==v)break;
            }
            if(u==1)printf("%d
    ",sz);
        }
    }
    int main()
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
        }
        tarjan(1);
        return 0;
    }
    G.cpp

    H.5129(题面已经修正)

    n个人的无向图,LJ为1和LJ已经认识的人,对于S,输出LJ可以认识的新朋友,对于Q x,输出1和x是否连通。

    并查集。

    坑点:

    1.LJ可以认识自己。

    2.n和m是相反的。

    #include<bits/stdc++.h>
    using namespace std;
    int f[1005];
    int find(int x)
    {
        return f[x]==x?x:f[x]=find(f[x]);
    }
    int main()
    {
        ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
        int n,m,t,g,val,k,v;
        cin>>t;
        while(t--)
        {
            cin>>m>>n;
            for(int i=1;i<=n;i++)f[i]=i;
            for(int i=1;i<=n;i++)
            {
                cin>>k;
                if(i==1)g=k;
                for(int j=0;j<k;j++)
                {
                    cin>>v;
                    if(i==1&&i==v)g--;
                    int fu=find(i),fv=find(v);
                    if(fu!=fv)f[fu]=fv;
                }
            }
            for(int i=1;i<=n;i++)f[i]=find(i);
            string s;
            int ans=0;
            for(int i=2;i<=n;i++)
                if(f[1]==f[i])
                    ans++;
            while(m--)
            {
                cin>>s;
                if(s[0]=='S')
                    cout<<ans-g<<'
    ';
                else
                {
                    cin>>val;
                    if(f[1]==f[val])cout<<"Yes!
    ";
                    else cout<<"No!
    ";
                }
            }
        }
        return 0;
    }
    H.cpp

    I.5166

    n个点构造一个哈夫曼树。

    贪心每次取两个最小的。

    #include<bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        priority_queue< int,vector<int>,greater<int> >q;
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            int a;
            cin>>a;
            q.push(a);
        }
        int sum=0;
        while(q.size()>1)
        {
            int a=q.top();q.pop();
            int b=q.top();q.pop();
            sum+=a+b;
            q.push(a+b);
        }
        cout<<sum;
        return 0;
    }
    I.cpp

    J.4992

    n次移动,(0,0)朝北出发,每次走ai步,走完后右转,如果路径冲突,输出移动了几次,否则输出OK。

    首先几何知识判断两条线段是否相交或重叠。

    通过观察发现当前这条线段最多和前面8条线段存在冲突。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
     
    const int MAX = 1000007, dx[] = { 0, 1, 0, -1 }, dy[] = { 1, 0, -1, 0 };
    int N, a[MAX];
     
    struct Point
    {
        int x, y;
        Point(int _x = 0, int _y = 0) :
            x(_x), y(_y) {}
    } points[MAX];
     
    // true, if intervals [a,b] and [c,d] have non-empty intersection
    bool overlap(int a, int b, int c, int d)
    {
        if (a > b) swap(a, b);
        if (c > d) swap(c, d);
        return !(b < c || d < a);
    }
     
    // true if line segments [a1,a2] and [b1,b2] have non-empty intersection
    bool intersect(Point a1, Point a2, Point b1, Point b2)
    {
        bool is_vertical_a = (a1.x == a2.x), is_vertical_b = (b1.x == b2.x);
        if (is_vertical_a && is_vertical_b)
            return a1.x == b1.x && overlap(a1.y, a2.y, b1.y, b2.y);
        if (!is_vertical_a && !is_vertical_b)
            return a1.y == b1.y && overlap(a1.x, a2.x, b1.x, b2.x);
        // make a horizontal and b vertical
        if (is_vertical_a)
        {
            swap(a1, b1);
            swap(a2, b2);
        }
        return !(
            max(a1.x, a2.x) < b1.x ||
            min(a1.x, a2.x) > b1.x ||
            max(b1.y, b2.y) < a1.y ||
            min(b1.y, b2.y) > a1.y);
    }
     
    int solve()
    {
        int x = 0, y = 0;
        for (int i = 0; i < N; ++i)
        {
            x += dx[i & 3] * a[i];
            y += dy[i & 3] * a[i];
            points[i + 1].x = x;
            points[i + 1].y = y;
            for (int j = max(0, i - 8); j < i - 2; ++j)
            if (intersect(points[j], points[j + 1], points[i], points[i + 1]))
                return i;
        }
        return -1;
    }
     
    int main()
    {
        while (scanf("%d", &N) == 1)
        {
            for (int i = 0; i < N; ++i)
                scanf("%d", a + i);
            int result = solve();
            if (result == -1)
                printf("OK
    ");
            else
                printf("%d
    ", result);
        }
     
        return 0;
    }
    J.cpp

    K.4541

    n个数,求插入个数最少的整数,使其成为一个回文数列。

    dp,答案是n-最长回文子序列的长度。

    设字符串为s,f(i,j)表示s[i..j]的最长回文子序列。 

    状态转移方程如下: 

    当i>j时,f(i,j)=0。 

    当i=j时,f(i,j)=1。 

    当i<j并且s[i]=s[j]时,f(i,j)=f(i+1,j-1)+2。 

    当i<j并且s[i]≠s[j]时,f(i,j)=max( f(i,j-1), f(i+1,j) )。 

    由于f(i,j)依赖i+1,所以循环计算的时候,第一维必须倒过来计算,从s.length()-1到0。 

    最后,s的最长回文子序列长度为f(0, s.length()-1)。

    可以发现计算第i行时只用到了第i+1行,所以可以滚动数组减少内存使用。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=10005;
    int a[N],n,dp[2][N];
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            memset(dp,0,sizeof dp);
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%d",&a[i]);
            int cnt=0;
            for(int i=n;i>=1;i--)
            {
                cnt^=1;
                memset(dp[cnt],0,sizeof dp[cnt]);
                dp[cnt][i]=1;
                for(int j=i+1;j<=n;j++)
                {
                    if(a[i]==a[j]) dp[cnt][j]=dp[cnt^1][j-1]+2;
                    else dp[cnt][j]=max(dp[cnt][j-1],dp[cnt^1][j]);
                }
            }
            printf("%d
    ",n-dp[cnt][n]);
        }
        return 0;
    }
    K.cpp

    L.4561

    n个人,1号为Sheldon,已知其余n-1个人投给了f[i]要买通需要花费c[i],1号需要投给1个人。最后1想要花最少的钱使得自己的票数>其他所有人的票数,求最少的钱。

    贪心+讨论

    这里每个人票数为p[i]。

    1投给目前票数最少的人(好好思考思考),然后考虑1需要x票能赢,那么其余人i只要p[i]>=x就需要买通p[i]-x+1个人,肯定买最便宜的,最后如果1还差k票,那么把所有没买通的人按c[i]排序再取k个最小。

    #include<bits/stdc++.h>
    using namespace std;
    vector<int>vec[105];
    int f[105],c[105],t,a;
    int main()
    {
        cin>>t;
        while(t--)
        {
            int n;
            cin>>n;
            for(int i=1;i<=n;i++)vec[i].clear();
            for(int i=2;i<=n;i++)cin>>f[i];
            for(int i=2;i<=n;i++)cin>>c[i];
            for(int i=2;i<=n;i++)vec[f[i]].push_back(c[i]);
            for(int i=1;i<=n;i++)sort(vec[i].begin(),vec[i].end());
            int M_P=1e9,M_POS=1;
            for(int i=2;i<=n;i++)
            {
                if((int)vec[i].size()<M_P)
                {
                    M_P=(int)vec[i].size();
                    M_POS=i;
                }
            }
            int sl=0;
            for(int i=1;i<=n;i++)if((int)vec[i].size()==M_P)sl++;
            if(sl==n)
            {
                int Minn=1e9,Minnp=1;
                for(int i=2;i<=n;i++)if((int)vec[i].size()>0&&vec[i][0]<Minn)Minn=vec[i][0],Minnp=i;
                vec[Minnp].push_back(0x3f3f3f3f);
            }
            else vec[M_POS].push_back(0x3f3f3f3f);
            int Min=1e9;
            for(int i=(int)vec[1].size();i<n;i++)
            {
                vector<int>prem[105],prr;
                int NEED=i-(int)vec[1].size();
                for(int j=2;j<=n;j++)prem[j]=vec[j];
                int sum=0;
                for(int j=2;j<=n;j++)
                {
                    if((int)prem[j].size()>=i)
                    {
                        int need=(int)prem[j].size()-i+1;
                        NEED-=need;
                        if(NEED<0)goto e;
                        for(int k=0;k<need;k++)sum+=prem[j][k];
                        for(int k=need;k<(int)prem[j].size();k++)prr.push_back(prem[j][k]);
                    }
                    else
                    {
                        for(int k=0;k<(int)prem[j].size();k++)
                            prr.push_back(prem[j][k]);
                    }
                }
                if(NEED>0)
                {
                    sort(prr.begin(),prr.end());
                    for(int j=0;j<NEED;j++)sum+=prr[j];
                }
                Min=min(Min,sum);
                e:;
            }
            cout<<Min<<endl;
        }
        return 0;
    }
    L.cpp

    M.2337

    已知Dick12岁,janepuff和spot相差s岁,yertle和puff相差p岁,yertle和spot相差y岁,Spot, Puff, Yertle和等于Dick,jane和,求Spot, Puff, Yertle的岁数。

    那么由确定关系,设yertle为x岁,那么spot为x + y, puff为x + p然后与s进行比较。

    #include<bits/stdc++.h>
    using namespace std;
    
    int main()
    {
        int n,s,p,y,t;
        cin>>n;
        while(n--)
        {
            cin>>s>>p>>y>>t;
            int sum=12+t;
            int temp=sum-y-p;
            int x=temp/3;
            if(temp%3==0)
                cout<<x+y<<" "<<x+p<<" "<<x<<endl;
            else if(temp%3==1)
            {
                if(s+p==y)
                    cout<<x+y+1<<" "<<x+p<<" "<<x<<endl;
                else
                    cout<<x+y<<" "<<x+p+1<<" "<<x<<endl;
            }
            else
                cout<<x+y+1<<" "<<x+p+1<<" "<<x<<endl;
        }
        return 0;
    }
    M.cpp
  • 相关阅读:
    滤镜
    android 判断网络是否断开
    U5
    android 界面跳转
    光影魔术手 图片压缩
    服务器绑定 独立ip
    Java 开源 SOCKET 框架
    spring aop ehcache
    呼叫中心
    华丽字体
  • 原文地址:https://www.cnblogs.com/taozi1115402474/p/10851429.html
Copyright © 2020-2023  润新知