• 2019 HZNU Winter Training Day 15 Comprehensive Training


    A - True Liars

    题意:

        那么如果一个人说另一个人是好人,那么如果这个人是好人,说明 对方确实是好人,如果这个是坏人,说明这句话是假的,对方也是坏人。

    如果一个人说另一个人是坏人,那么如果这个人是好人,说明对方是坏人,如果这个是坏人,说明 对方是好人。

    也就是如果条件是yes说明这两个是相同集合的,否则是两个不同的集合。

    思路:

        用r[i]表示i结点与根结点的关系,0为相同集合,1为不同集合。这是一个经典的并查集问题。

        这样处理之后,还需要判断是否唯一

        我们通过并查集,可以将所有人分为若干个集合,其中对于每一个集合,又分为两个集合(好人和坏人,但是不知道哪些是好人,哪些是坏人,我们只有相对关系)

        接下来就是从所有大集合中的两个小集合取一个,组成好人集合,判断是否唯一。

        背包问题,dp[i][j]表示前i个大集合,好人为j个的方案有多少种,或者dp[i][j]表示当前好人i个,坏人j个的情况有多少种

        如果dp[cnt][p1]!=1说明方案不唯一,或者无解。

        输出方案就是加个pre数组,从后往前递推呢。

    代码:

    /*
    POJ 1417
    */
    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    #include <vector>
    #include <string>
    using namespace std;
    
    const int MAXN=610;
    int F[MAXN];
    int val[MAXN];
    int find(int x)
    {
        if(F[x]==-1)return x;
        int tmp=find(F[x]);
        val[x]+=val[F[x]];
        val[x]%=2;
        return F[x]=tmp;
    }
    int a[MAXN][2];//a[i][0],a[i][1]表示每个大集合分成两部分的个数
    vector<int>b[MAXN][2];
    bool used[MAXN];
    int dp[MAXN][MAXN/2];
    int pre[MAXN][MAXN/2];
    int main()
    {
        int n,p1,p2;
        while(scanf("%d%d%d",&n,&p1,&p2)==3)
        {
            if(n==0 && p1==0 && p2==0)break;
            memset(F,-1,sizeof(F));
            memset(val,0,sizeof(val));
            int u,v;
            char str[10];
            while(n--)
            {
                scanf("%d%d%s",&u,&v,&str);
                int tmp;
                if(str[0]=='y')//相同
                  tmp=0;
                else tmp=1;//相反
                int t1=find(u),t2=find(v);
                if(t1!=t2)
                {
                    F[t1]=t2;
                    val[t1]=(val[v]-val[u]+tmp+2)%2;
                }
            }
            for(int i=0;i<MAXN;i++)
            {
                b[i][0].clear();
                b[i][1].clear();
                a[i][0]=0;
                a[i][1]=0;
            }
            memset(used,false,sizeof(used));
            int cnt=1;
            for(int i=1;i<=p1+p2;i++)
              if(!used[i])
              {
                  int tmp=find(i);
                  for(int j=i;j<=p1+p2;j++)
                  {
                      if(find(j)==tmp)
                      {
                          used[j]=true;
                          b[cnt][val[j]].push_back(j);
                          a[cnt][val[j]]++;
                      }
                  }
                  cnt++;
              }
            memset(dp,0,sizeof(dp));
            dp[0][0]=1;
            for(int i=1;i<cnt;i++)
            {
                for(int j=p1;j>=0;j--)
                {
                    if(j-a[i][0]>=0 && dp[i-1][j-a[i][0]])
                    {
                        dp[i][j]+=dp[i-1][j-a[i][0]];
                        pre[i][j]=j-a[i][0];
                    }
    
                    if(j-a[i][1]>=0 && dp[i-1][j-a[i][1]])
                    {
                        dp[i][j]+=dp[i-1][j-a[i][1]];
                        pre[i][j]=j-a[i][1];
                    }
    
                }
            }
            if(dp[cnt-1][p1]!=1)
            {
                printf("no
    ");
            }
            else
            {
                vector<int>ans;
                ans.clear();
                int t=p1;
                //printf("%d
    ",cnt);
    
                for(int i=cnt-1;i>=1;i--)
                {
                    int tmp=t-pre[i][t];
                    //printf("%d
    ",i);
                    //printf("%d  %d
    ",t,tmp);
                    if(tmp==a[i][0])
                    {
                        for(int j=0;j<a[i][0];j++)
                          ans.push_back(b[i][0][j]);
                    }
                    else
                    {
                        for(int j=0;j<a[i][1];j++)
                          ans.push_back(b[i][1][j]);
                    }
                    t=pre[i][t];
                }
    
                sort(ans.begin(),ans.end());
                for(int i=0;i<ans.size();i++)
                  printf("%d
    ",ans[i]);
                printf("end
    ");
            }
    
        }
        return 0;
    }
    View Code

    B - The Shortest Path in Nya Graph

    题意:有n个点 , m条无向边 ,每条边都是有权值, 并且每个点属于一个楼层 ,楼层上的点到可以到相邻楼层的任意一点 ,但是要花费 c 。没有点的相邻楼层不能互达。求 1 到 n的最小花费。

    思路:图建好了就是裸的最短路了。但是建图有点麻烦,参考了别人的代码之后才明白为什么要这样建图。
          把楼层看成一个点,第i层可以看成第n+i个点。楼层与该楼层上的点建边,边权为0,单向;楼层与
          相邻楼层建边,边权为C,双向;相邻楼层上的点与该楼层建边,边权为C,单向。

    代码:

    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<vector>
    #include<queue>
    #define N 200100
    #define ll long long
     
    using namespace std;
    const int inf=0x3f3f3f3f;
    int n,m,c;
    int lay[N];
    bool hava[N];
     
    bool vis[N];
    int cnt[N];
    int dist[N];
    struct Edge {
        int v;
        int cost;
        Edge(int _v=0,int _c=0):v(_v),cost(_c) {}
        bool operator <(const Edge &r)const {
            return cost>r.cost;
        }
    };
    vector<Edge>E[N];
    void addedge(int u,int v,int w) {
        Edge it;
        it.v=v;
        it.cost=w;
        E[u].push_back(it);
    }
     
    void Dijk(int n,int start) { //点的编号从1开始
        memset(vis,false,sizeof(vis));
        for(int i=1; i<=n*2; i++)dist[i]=inf;
        priority_queue<Edge>que;
        while(!que.empty())que.pop();
        dist[start]=0;
        que.push(Edge(start,0));
        Edge tmp;
        while(!que.empty()) {
            tmp=que.top();
            que.pop();
            int u=tmp.v;
            if(vis[u])continue;
            vis[u]=true;
            for(int i=0; i<E[u].size(); i++) {
                int v=E[tmp.v][i].v;
                int cost=E[u][i].cost;
                if(!vis[v]&&dist[v]>dist[u]+cost) {
                    dist[v]=dist[u]+cost;
                    que.push(Edge(v,dist[v]));
                }
     
            }
        }
    }
     
    int main() {
       // freopen("test.in","r",stdin);
        int t;
        cin>>t;
        int ca=1;
        while(t--) {
            for(int i=0; i<=n*2+1; i++)E[i].clear();
            scanf("%d%d%d",&n,&m,&c);
            memset(hava,0,sizeof hava);
            for(int i=1; i<=n; i++) {
                scanf("%d",&lay[i]);
                hava[lay[i]]=true;
            }
            int u,v,cost;
            for(int i=1; i<=m; i++) {
                scanf("%d%d%d",&u,&v,&cost);
                addedge(u,v,cost);
                addedge(v,u,cost);
            }
            if(n<=1) {
                printf("Case #%d: 0
    ",ca++);
                continue;
            }
     
            for(int i=1; i<n; i++) {
                if(hava[i]&&hava[i+1]) {
                    addedge(n+i,n+i+1,c);
                    addedge(n+1+i,n+i,c);
                }
            }
            for(int i=1; i<=n; i++) {
                addedge(lay[i]+n,i,0);
                if(lay[i]>1)addedge(i,lay[i]-1+n,c);
                if(lay[i]<n)addedge(i,lay[i]+1+n,c);
            }
            Dijk(n,1);
            printf("Case #%d: %d
    ",ca++,dist[n]>=inf?-1:dist[n]);
        }
        return 0;
    }
    View Code

    C - The Super Powers

    题意:给你一个关于超级幂数的定义,只要一个数是至少两个数的幂,即为超级幂数。例如64=8*8=4*4*4。输出1~2^64-1内所有的超级幂数。

    思路:一开始的思想暴力,但是肯定很慢。有两个比较重要的思路:① 找num^x<2^64-1的时候,尝试两边取对数,然后确定x<ln(2^64-1)/ln(num),x在4~ln(2^64-1)/ln(num)里取。② 只有合数的时候才能产生超级幂数,然后判断是否为素数即可。

      还有很重要的一点,pow会出错。谨慎使用,wa了很多次,用快速幂才ac。

      扔进set里遍历输出即可。

    代码:

     1 /*
     2  I have a dream!A AC deram!!
     3  orz orz orz orz orz orz orz orz orz orz orz
     4  orz orz orz orz orz orz orz orz orz orz orz
     5  orz orz orz orz orz orz orz orz orz orz orz
     6 
     7  */
     8 
     9 #include<iostream>
    10 #include<cstdio>
    11 #include<cstdlib>
    12 #include<cstring>
    13 #include<cmath>
    14 #include<string>
    15 #include<algorithm>
    16 #include<vector>
    17 #include<queue>
    18 #include<set>
    19 #include<stack>
    20 using namespace std;
    21 typedef long long ll;
    22 typedef unsigned long long ull;
    23 const int maxn = 1e4 + 5;
    24 const int N = 2100;
    25 #define pa pair<int,int>
    26 inline int read()
    27 {
    28     int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar())if (ch == '-')f = -1;
    29     for (; isdigit(ch); ch = getchar())x = x * 10 + ch - '0'; return x * f;
    30 }
    31 
    32 bool isPrime(int n)
    33 {
    34     if (n <= 3)
    35         return n > 1;
    36     else if (n % 2 == 0 || n % 3 == 0)
    37         return false;
    38     else
    39     {
    40         for (int i = 5; i * i <= n; i += 6)
    41             if (n % i == 0 || n % (i + 2) == 0)
    42                 return false;
    43     }
    44     return true;
    45 }
    46 
    47 ull qsm(int a, int b)
    48 {
    49     ull ans = 1, base = a;
    50     while (b != 0) {
    51         if (b & 1 != 0) {
    52             ans *= base;
    53         }
    54         base *= base;
    55         b >>= 1;
    56     }
    57     return ans;
    58 }
    59 
    60 
    61 int main()
    62 {
    63     set<ull>ans;
    64     ans.insert(1);
    65     ull maxx = 18446744073709551615;
    66     for (int num = 2; num < 1e5; num++)
    67     {
    68         if (pow(num, 4) > maxx) break;
    69         double m = log(maxx) / log(num);
    70         for (int i = 4; i < m; i++)
    71         {
    72             if (isPrime(i)) continue;
    73             ull p = qsm(num, i);
    74             ans.insert(p);
    75         }
    76     }
    77 
    78     set<ull>::iterator it;
    79     //int cnt = 0;
    80     for (it = ans.begin(); it != ans.end(); it++)
    81     {
    82         //cnt++;
    83         //if (cnt == 10) break;
    84         printf("%llu
    ", *it);
    85     }
    86     return 0;
    87 }
    View Code

    D - Music Festival

    题意:给你n组区间,每个居间都带有权值,让你选取一些区间使得区间不想交并且权值最大(要每组都至少有一个区间被选到)。

    思路:n最多十组,我们就可以用二进制来记录当前唱歌的状态,然后离散化区间点(这样我们就可以用连续的点去表示这些区间),这样就有dp【i】【j】,i表示当前的区间点,j表示当前的状态,dp【i1】【j1】=dp【i】【j】+num【k】。每次寻找当前点往右 能更新的最近的一个区间(一切切的一切都是膜拜大佬的博客来的,离散化真是个好东西)
    ---------------------
    作者:liexss
    来源:CSDN
    原文:https://blog.csdn.net/liexss/article/details/83511980

    代码:

     1 #include<stdio.h>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<map>
     6 #include<iostream>
     7 using namespace std;
     8 struct inst {
     9     int x, y;
    10     int sud;
    11     int id;
    12 };
    13 inst ax[1100];
    14 int dp[2100][1100];
    15 int bn[2100];
    16 int maxn[1100];
    17 int tot, cnt;
    18 map<int, int>q;
    19 int cmp(inst a, inst b) {
    20     if (a.x!=b.x)return a.x < b.x;
    21     else return a.y < b.y;
    22 }
    23 int binary_s(int x) {
    24     int l = 0;
    25     int r = tot-1;
    26     int ans = tot-1;
    27     while (l <= r) {
    28         int mid = (l + r) / 2;
    29         if (ax[mid].x >= x) {
    30             ans = mid;
    31             r = mid - 1;
    32         }
    33         else l = mid + 1;
    34     }
    35     if (x > ax[ans].x) ans++;
    36     return ans;
    37 }
    38 int main(void) {
    39     int n;
    40     scanf("%d", &n);
    41     tot = 0;
    42     cnt = 0;
    43     q.clear();
    44     memset(maxn, 0x8f, sizeof(maxn));
    45     memset(dp, 0x8f, sizeof(dp));
    46     for (int i = 1; i <= n; i++) {
    47         int m;
    48         scanf("%d", &m);
    49         for (int z = 0; z < m; z++) {
    50             scanf("%d %d %d", &ax[tot].x, &ax[tot].y,&ax[tot].sud);
    51             ax[tot].id = i-1;
    52             bn[cnt++] = ax[tot].x;
    53             bn[cnt++] = ax[tot].y;
    54             tot++;
    55         }
    56     }
    57     sort(bn, bn + cnt);
    58     cnt = unique(bn,bn + cnt) - bn;
    59     sort(ax, ax + tot, cmp);
    60     for (int i = 0; i < cnt; i++) {
    61         q[bn[i]] = i;
    62     }
    63     for (int i = 0; i < tot; i++) {
    64         ax[i].x = q[ax[i].x];
    65         ax[i].y = q[ax[i].y];
    66     }
    67     dp[0][0] = maxn[0] = 0;
    68     for (int i = 0; i < cnt; i++) {
    69         for (int j = 0; j < (1 << n); j++) {
    70             dp[i][j] = maxn[j] = max(dp[i][j], maxn[j]);
    71             if (dp[i][j] < 0) continue;
    72             int pos=binary_s(i);
    73             int pre = -1;
    74             for (int z = pos; z < tot; z++) {
    75                 if (pre == -1 || pre == ax[z].x) pre = ax[z].x;
    76                 else break;
    77                 int x1 = ax[z].y;
    78                 int jj = j | (1 << ax[z].id);
    79                 int sum = dp[i][j] + ax[z].sud;
    80                 dp[x1][jj] = max(dp[x1][jj], sum);
    81             }
    82         }
    83     }
    84     if (maxn[(1 << n) - 1] >= 0) printf("%d
    ", maxn[(1 << n) - 1]);
    85     else printf("-1
    ");
    86     return 0;
    87 }
    View Code

    E - Nature Reserve

    题意:在二维坐标上,有动物的栖息地和一条河流,河流在y=0上,即为X轴。现在要建一个圆形的动物保护区,让动物都在里面,同时这个圆要求和X轴相切。因为只能相切,如果出现动物在X轴两侧的情况输出-1,即不能满足情况。

    思路:我们二分半径,然后由于固定了与X轴相切,我们对于每一个点,就可以算出这个点在圆上的时候的圆心的极限距离。然后我们就可以求得每一个点的圆心的区间范围。然后所有点的区间范围都相交,那么证明这个半径可行,否则不可行。

    代码:如果你的电脑和我的一样辣鸡,代码基本相同样例跑不出来,可能是精度的问题,建议您不要取很大的数字,取小点吧。

     1 /*
     2  I have a dream!A AC deram!!
     3  orz orz orz orz orz orz orz orz orz orz orz
     4  orz orz orz orz orz orz orz orz orz orz orz
     5  orz orz orz orz orz orz orz orz orz orz orz
     6 
     7  */
     8 
     9 #include<iostream>
    10 #include<cstdio>
    11 #include<cstdlib>
    12 #include<cstring>
    13 #include<cmath>
    14 #include<string>
    15 #include<algorithm>
    16 #include<vector>
    17 #include<queue>
    18 #include<set>
    19 #include<stack>
    20 using namespace std;
    21 typedef long long ll;
    22 typedef unsigned long long ull;
    23 const int maxn = 1e5 + 10;
    24 #define pa pair<int,int>
    25 
    26 inline int read()
    27 {
    28     int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar())if (ch == '-')f = -1;
    29     for (; isdigit(ch); ch = getchar())x = x * 10 + ch - '0'; return x * f;
    30 }
    31 
    32 double x[maxn], y[maxn];
    33 int N;
    34 
    35 bool check(long double R)
    36 {
    37     long double l = -100000000000000000.0, r = 100000000000000000.0, t;
    38     for (int i = 1; i <= N; i++)
    39     {
    40         if (2 * R < y[i])
    41             return 0;
    42         t = sqrt(R*R - (R - y[i])*(R - y[i]));
    43         if (l < x[i]-t) l = x[i] - t;
    44         if (r > t+x[i]) r = t + x[i];
    45     }
    46     return l < r;
    47 }
    48 
    49 int main()
    50 {
    51     scanf("%d", &N);
    52     for (int i = 1; i <= N; i++)
    53         scanf("%lf %lf", &x[i], &y[i]);
    54     for (int i = 1; i <= N; i++)
    55     {
    56         if (y[i] * y[N] < 0)
    57         {
    58             printf("-1
    ");
    59             return 0;
    60         }
    61         y[i] = y[i] > 0 ? y[i] : -y[i];
    62     }
    63 
    64     long double l = 0, r = 100000000000000000.0, mid;
    65     for(int i = 1;i <= 100;i++)
    66     {
    67         mid = (l + r) / 2.0;
    68         if (check(mid))
    69             r = mid;
    70         else
    71             l = mid;
    72     }
    73     printf("%.10Lf
    ", mid);
    74     
    75     return 0;
    76 }
    View Code

    F - Graph And Its Complement

    题意:给出n,a,b,问,是否有这样的一个图,有n个节点,分成a块,现将两两节点之间有边的把边删除,两两节点之间无边的建边,使得形成的图分成b块。如果有,输出YES,并且输出这个图的邻接矩阵,否则输出NO。这题难就难在是否能推出结论以及答案的输出。

    思路:

    任何一个图,不管分成多少块,经过上述操作后,必然变成一个联通图。

    证:有n个节点,分成m块,任取一块,经过上述操作后,所取的这一块内的任意节点必定与其他块的所有节点相连!

    这个结论换句话说就是,a和b里面,至少有一个数是1!知道这个结论就简单了,首先排除所有不含1的情况,然后,b==1的情况,我们将图分成a块,直接另前a-1块都只有一个节点,最后1块包含剩下的节点就行了。当然,对于a==1,只要将要输出反过来一下就可以了(注意,这里要讨论一下a和b都为1的情况,当n==2和n==3时,是不行的直接排除,其他情况都是可行的,特殊处理一下a和b都等于1的输出)
    ---------------------
    作者:JIA-YAO
    来源:CSDN
    原文:https://blog.csdn.net/qq_41874469/article/details/80658410

    代码:

    #include "iostream"
    #include "algorithm"
    using namespace std;
    int n,a,b;
    char ch1='0',ch2='1';
    int main() {
        cin>>n>>a>>b;
        if (a!=1&&b!=1||a==1&&b==1&&n<=3&&n>=2||a>n||b>n) {cout<<"NO"<<endl; return 0;}
        cout<<"YES"<<endl;
        if (a==1) swap(a,b), swap(ch1,ch2);
        for (int i=0;i<n;i++) {
            for (int j=0;j<n;j++) {
                cout<<(i==j?'0':(i+1==j&&j>=a||j+1==i&&i>=a?ch1:ch2));
            }
            cout<<endl;
        }
    }
    View Code
  • 相关阅读:
    DM数据库disql的使用 Disql disql 达梦数据库Disql
    移动端禁止蒙层下的页面滚动
    移动端如何自动适配px
    使用Vant做移动端对图片预览ImagePreview和List的理解
    uniapp中使用uView组件库
    h5使用vuephotopreview 做全屏预览
    jsonview的实现
    PC端自适应使用rem 移动端适配升级版
    axios解决跨域问题(vuecli3.0)
    vs code 配置git path
  • 原文地址:https://www.cnblogs.com/Tangent-1231/p/10391395.html
Copyright © 2020-2023  润新知