AtCoder Beginner Contest 068

A - ABCxxx

题意:

给出n,输出“ABCn”就可以了,纯水题。

B - Break Number

题意:

给出n,找出从1到n的闭区间内能够被2整除最多次的数。

思路:

直接模拟。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3  
 4 int main()
 5 {
 6     int n;
 7  
 8     scanf("%d",&n);
 9  
10     int maxn = 0;
11     int ans = 1;
12  
13     for (int i = 1;i <= n;i++)
14     {
15         int tmp = i;
16         int cnt = 0;
17  
18         while (tmp % 2 == 0)
19         {
20             tmp /= 2;
21             cnt++;
22         }
23  
24         if (cnt > maxn)
25         {
26             maxn = cnt;
27             ans = i;
28         }
29     }
30  
31     printf("%d",ans);
32  
33     return 0;
34 }

C - Cat Snuke and a Voyage

题意:

有n个城市,其中第一个和第n个城市是不直接相连的。接下来给出m个关系a,b,表示有m种航线,a可以单向到b。问从1到n可否只乘坐2条航线。

思路:

我的思路是bfs搜一遍,如果dis[1] = 0,看看那么dis[n] == 2?

但是有更简洁的思路,那么就是用floyed算法的思想,有向图的传递闭包。用两个数组from和to,当1到k有航线的时候,from[k] = 1;当k到n有航线的时候,to[k] = 1。则当from[i]和to[i]同时为1的时候,说明可以只乘坐两条航线。

代码:

bfs()版本

 1 #include <stdio.h>
 2 #include <vector>
 3 #include <queue>
 4 #include <string.h>
 5 using namespace std;
 6  
 7 int d[200005];
 8 const int inf = 200005;
 9 vector<int> v[200005];
10  
11 void bfs(void)
12 {
13     d[1] = 0;
14  
15     queue<int> q;
16  
17     q.push(1);
18  
19     while (!q.empty())
20     {
21         int t = q.front();q.pop();
22  
23         for (int i = 0;i < v[t].size();i++)
24         {
25             int tt = v[t][i];
26  
27             if (d[t] + 1 < d[tt])
28             {
29                 d[tt] = d[t] + 1;
30  
31                 q.push(tt);
32             }
33         }
34     }
35 }
36  
37 int main()
38 {
39     memset(d,inf,sizeof(d));
40  
41     int n,m;
42  
43     scanf("%d%d",&n,&m);
44  
45     for (int i = 1;i <= m;i++)
46     {
47         int a,b;
48  
49         scanf("%d%d",&a,&b);
50  
51         v[a].push_back(b);
52     }
53  
54     bfs();
55  
56     if (d[n] == 2) printf("POSSIBLE\n");
57     else printf("IMPOSSIBLE\n");
58  
59     return 0;
60 }

floyed版本:

#include <stdio.h>
#include <string.h>

bool from[200005];
bool to[200005];

int main()
{
    int n,m;

    scanf("%d%d",&n,&m);

    for (int i = 0;i < m;i++)
    {
        int a,b;

        scanf("%d%d",&a,&b);

        if (a == 1) from[b] = 1;
        if (b == n) to[a] = 1;
    }

    bool ans = 0;

    for (int i = 2;i < n;i++)
    {
        if (from[i] && to[i])
        {
            ans = 1;
            break;
        }
    }

    if (ans) printf("POSSIBLE\n");
    else printf("IMPOSSIBLE\n");

    return 0;
}

D - Decrease (Contestant ver.)

 题意:

现在有一个包含n个非负整数的序列,现在执行下列操作直到数组中最大的元素小于n。

operation:找出数组中最大的元素,使之减去n,其余的所有元素加1。

可以证明经过有限次的操作可以使得数组中最大的元素小于或者等于n-1。

现在给出一个k,找出一个数列满足刚好经过k次操作后满足最大元素小于等于n-1。

思路:

看题解补的,考虑逆序操作,即数组中的一个元素加n,并且加后保证这个元素是数组中最大的,然后其它元素减1,所有的元素均为非负数。

考虑0,1,……,n-1这个序列,是满足最后的条件的,那么如果经过k次逆序操作后,数组中都是非负数,那么就这个数组就是我们要求的数组。

0,1,……,n-1这个数组经过n次操作后,可以变成1,2,……,n,2*n次操作后可以变成2,3,……,n+1。不难发现,经过n次操作,数组中的所有元素都会增加1。所以最终我们求的序列就是0~n-1所有的元素增加 k / n,然后暴力模拟 k % n次操作后得到的序列,它一定是合法的。

n如何选取呢,直接选取最大的就可以了,即50。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5  
 6 long long a[55];
 7  
 8 int main()
 9 {
10     long long k;
11  
12     scanf("%lld",&k);
13  
14     for (int i = 0;i < 50;i++)
15         a[i] = i;
16  
17     for (int i = 0;i < 50;i++)
18     {
19         a[i] += k / 50;
20     }
21  
22     for (int i = 0;i < k % 50;i++)
23     {
24         sort(a,a+50);
25  
26         a[0] += 50;
27  
28         for (int i = 1;i < 50;i++)
29             a[i]--;
30     }
31     
32     printf("50\n");
33     
34     for (int i = 0;i < 49;i++) printf("%lld ",a[i]);
35     printf("%lld",a[49]);
36     return 0;
37 }

 

posted @ 2017-07-30 09:38  qrfkickit  阅读(199)  评论(0编辑  收藏  举报