SDNU_ACM_ICPC_2019_Winter_Practice_6th

A - The 3n+1 problem

题目背景就是著名的冰雹猜想,要求是给你两个数 a , b a, b a,b, 让你求 [ a , b ] [a,b] [a,b]中所有的数进行该猜想运算时最大的运算次数。题目数据较弱,直接暴力模拟计算过程即可( P S : PS: PS数组打表会RE, 且 a , b a,b a,b大小关系不定)
AC代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
int main()
{
    int a, b;
    while (~scanf("%d %d", &a, &b)) {
        cout << a << " " << b << " " ;
        if (a > b)  swap(a, b);
        int ans = 0;
        for (int i = a; i <= b; ++i) {
            ll k = i;
            int tmp = 1;
            while (k != 1) {
                if (k % 2 == 0) k /= 2;
                else    k = 3*k+1;
                tmp++;
            }
            ans = max(ans, tmp);
        }
        cout << ans << '\n';
    }
    return 0;
}

B - Let’s Play Magic!

S a m p l e &ThickSpace; o u t p u t : Sample\;output: Sampleoutput:
Q H &ThickSpace; 4 C &ThickSpace; A S &ThickSpace; 8 D &ThickSpace; K H &ThickSpace; 2 S &ThickSpace; 7 D &ThickSpace; 5 C &ThickSpace; T H &ThickSpace; J H &ThickSpace; 3 S &ThickSpace; 6 C &ThickSpace; 9 D QH \; 4C \; AS \; 8D \; KH \; 2S \; 7D \; 5C \; TH \; JH \; 3S \; 6C \;9D QH4CAS8DKH2S7D5CTHJH3S6C9D

  • s t e p 1 step1 step1: 1, 2, 3 → \to A S AS AS , 删除 A S AS AS \quad A C E = 3 ACE = 3 ACE=3
  • s t e p 2 step2 step2: 1, 2, 3 → \to 2 S 2S 2S,删除 2 S 2S 2S \quad T W O = 3 TWO = 3 TWO=3
  • s t e p 3 step3 step3: 1, 2, 3, 4, 5 → \to 3 S 3S 3S, 删除 3 S 3S 3S \quad T H R E E = 5 THREE = 5 THREE=5
  • ⋯ \cdots

这题我们就是将 c a r d card card逐次的插入,已插入的位置可以标记下来,有点像约瑟夫环的逆过程
AC代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 55;
string s1[maxn], s2[maxn];
int indexs[maxn];

int main()
{
    int n;
    while (~scanf("%d", &n), n) {
        for (int i = 1; i <= n; ++i) {
            cin >> s1[i] >> s2[i];
            indexs[i] = -1;
        }
        for (int i = 1, j = 1; i <= n; ++i) {
            for (int k = s2[i].size(); ; j = j%n + 1) {
                if (indexs[j] == -1 && --k == 0) break;
            }
            indexs[j] = i;
        }
        for (int i = 1; i <= n; ++i) {
            if (i != 1) cout << " " ;
            cout << s1[indexs[i]] ;
        }
        cout << '\n';
    }
    return 0;
}

C - Cube painting

无论立方体如何旋转,对立面一定是不变的。通过前六个字符确定对立面之后,看旋转后的立方体的对立面与原先是否一样即可,注意顺序可能不同。
也可以把每个面旋转到第一个面,然后第一个面与它对应的面不动再进行四次旋转,判断。
AC代码:

#include <bits/stdc++.h>
using namespace std;

string s, str[3], cube, cube2;

int main()
{
	while (getline(cin, s)) {
		for (int i = 0; i < 3; ++i) str[i] = "";
		str[0] += s[0];
		str[1] += s[1];
		str[2] += s[2];
		str[0] += s[5];
		str[1] += s[4];
		str[2] += s[3];
		cube = cube2 = "";
		cube += s[6];
		cube += s[11];
		cube2 += s[11];
		cube2 += s[6];
		int i;
		for (i = 0; i < 3; ++i) {
			if (cube == str[i] || cube2 == str[i]) {
				str[i] = "\0";
				break;
			}
		}
		if (i == 3) {
			cout << "FALSE" << '\n';
			continue;
		}
		cube = cube2 = "";
		cube += s[7];
		cube += s[10];
		cube2 += s[10];
		cube2 += s[7];
		for (i = 0; i < 3; ++i) {
			if (cube == str[i] || cube2 == str[i]) {
				str[i] = "\0";
				break;
			}
		}
		if (i == 3) {
			cout << "FALSE" << '\n';
			continue;
		}
		cube = cube2 = "";
		cube += s[8];
		cube += s[9];
		cube2 += s[9];
		cube2 += s[8];
		for (i = 0; i < 3; ++i) {
			if (cube == str[i] || cube2 == str[i])  break;
		}
		if (i == 3) {
			cout << "FALSE" << '\n';
			continue;
		}
		cout << "TRUE" << '\n';
	}
	return 0;
}

D - A New Growth Industry

一个英语阅读题,题意是数组中的这个数和它上下左右四个数加起来的和对应在d表中能查到一个数,再把这个数和原来数组元素的相加 (大于3的为3,小于0的设为0.),最后根据对应符号输出
AC代码:

#include <bits/stdc++.h>
using namespace std;

int main()
{
	int T;
	cin >> T;
	while(T--) {
		int a[22][22] = {0};
		int b[22][22] = {0};
		int d[16];
		int day;
		char c[5] = {".!X#"};
		scanf("%d", &day);
		for(int i = 0; i < 16; ++i) scanf("%d",&d[i]);
		for(int i = 1; i <= 20; ++i) {
			for(int j = 1; j <= 20; ++j)  scanf("%d", &a[i][j]);
		}
		while(day--) {
            for(int i = 1; i <= 20; ++i) {
                for(int j = 1; j <= 20; ++j) {
                    b[i][j] = a[i][j] + a[i-1][j] + a[i+1][j] + a[i][j-1] + a[i][j+1];
                }
            }
            for(int i = 1; i <= 20; ++i) {
                for(int j = 1; j <= 20; ++j) {
                    a[i][j] += d[b[i][j]];
                    if(a[i][j] > 3)   a[i][j] = 3;
                    else if(a[i][j] < 0)  a[i][j] = 0;
                }
            }
		}
        for(int i = 1; i <= 20; ++i) {
            for(int j = 1; j <= 20; ++j) cout << c[a[i][j]];
            cout << '\n';
        }
        if(T!=0)    cout << '\n';
	}
	return 0;
}

E - Humble Numbers

质因子为2,3,5 or 7的数为 h u m b e r &ThickSpace; n u m b e r humber\;number humbernumber, 对所有 h u m b l e &ThickSpace; n u m b e r humble\;number humblenumber排序之后问你第几个数是多少
我们可以打表对2,3,5,7分别进行计算,每次只要让 a [ i ] a[i] a[i]等于最小的那一个,再让其相应的倍数++
AC代码:

#include <bits/stdc++.h>
using namespace std;

int a[5850];

void init()
{
    a[1] = 1;
    int x2 = 1, x3 = 1, x5 = 1, x7 = 1;
    for (int i = 2; i <= 5845; ++i) {
        a[i] = min(min(a[x2]*2, a[x3]*3), min(a[x5]*5, a[x7]*7));
        if(a[i] == a[x2]*2)   x2++;
        if(a[i] == a[x3]*3)   x3++;
        if(a[i] == a[x5]*5)   x5++;
        if(a[i] == a[x7]*7)   x7++;
    }
}
int main()
{
    init();
    int n;
    while(~scanf("%d",&n),n)
    {
        if(n % 100 == 11 || n%100 == 12 || n%100 == 13)
            printf("The %dth humble number is %d.\n",n,a[n]);
        else if(n%10 == 1)
            printf("The %dst humble number is %d.\n",n,a[n]);
        else if(n%10 == 2)
            printf("The %dnd humble number is %d.\n",n,a[n]);
        else if(n%10 == 3)
            printf("The %drd humble number is %d.\n",n,a[n]);
        else
            printf("The %dth humble number is %d.\n",n,a[n]);
    }
    return 0;
}

F - hide handkerchief

n n n个圈围成环,从随机一点开始,每隔 m − 1 m-1 m1个圈涂一次色,问是否能将 n n n个圈全部染色
稍微造几个数据就能知道,如果 g c d ( n , m ) = 1 gcd(n, m) = 1 gcd(n,m)=1, 那么一定能在 n n n次下染色完成,若 g c d ( n , m ) &ThickSpace; ! = 1 gcd(n, m)\;!= 1 gcd(n,m)!=1, 那么一定会产生循环
AC代码:

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n, m;
    while (~scanf("%d %d", &n, &m)) {
        if (n + m == -2)    break;
        if (__gcd(n, m) == 1) cout << "YES" << '\n';
        else    cout << "POOR Haha" << '\n';
    }
    return 0;
}

G - Robot Motion

建图之后,按照"N, S, E, W"方向按部就班的走就可以了,同时记录步数,在走过的位置vis标记,判断是否成环
AC代码:

#include <bits/stdc++.h>
using namespace std;

int a,b,c;
char maps[15][15];
int vis[15][15];

void solve()
{
    int x = 0, y = c-1;
    int circle = 0, step = 0, step2 = 0;
    vis[x][y] = 1;
    while(1)
    {
        if(maps[x][y]== 'N')   x--;
        else if(maps[x][y] == 'W')    y--;
        else if(maps[x][y] == 'S')   x++;
        else if(maps[x][y] == 'E')    y++;
        if(y<0 || x<0 || x>=a || y>=b)    break;
        if(vis[x][y] == 0) {
            vis[x][y] = 1;
            step++;
        }
        else if(vis[x][y] == 1) {
            vis[x][y] = 2;
            step2++;
            circle = 1;
        }
        else if(vis[x][y] == 2) break;
    }
    if(circle == 1) {
        printf("%d step(s) before a loop of %d step(s)\n", step-step2+1, step2);
    }
    else printf("%d step(s) to exit\n", step+1);
}
int main()
{
    while(~scanf("%d %d", &a, &b) && a+b) {
        scanf("%d",&c);
        memset(vis, 0, sizeof(vis));
        for(int i = 0; i < a; ++i) scanf("%s", maps[i]);
        solve();
    }
    return 0;
}

H - XK Segments

给你一个数组,问你满足 ( a [ i ] , a [ j ] ) (a[i], a[j]) (a[i],a[j])中有 k k k个数为 x x x的倍数的组数有多少个
先排序,然后以 a [ i ] a[i] a[i]为基准二分查找 a [ j ] a[j] a[j]的位置, l e f t = ( a [ i ] − a [ i ] % x ) + k x left = (a[i]-a[i]\%x)+kx left=(a[i]a[i]%x)+kx, r i g h t = l e f t + x right = left+x right=left+x
注意这道题会爆int
AC代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e5+10;
ll a[maxn];

ll binary_searchs(ll l, ll r, ll key)
{
    while(l <= r){
        ll mid = (l+r)/2;
        if(a[mid] >= key) r = mid-1;
        else l = mid+1;
    }
    return l;
}
int main()
{
    ll n, x, k;
    cin >> n >> x >> k;
    ll ans = 0;
    for(ll i = 0; i < n; i++){
        scanf("%lld", &a[i]);
    }
    sort(a, a+n);
    for(ll i = 0; i < n; i++){
        ll t = a[i]%x;
        ll l = a[i] + (x-t) % x + (k-1)*x;
        ll r = l + x;
        if(!k){
            l = a[i];
            r = a[i] + (x-t)%x;
        }
        l = binary_searchs(0, n-1, l);
        r = binary_searchs(0, n-1, r);
        ans += r-l;
    }
    cout << ans << '\n';
    return 0;
}

I - Funky Numbers

给你一个数 A A A, 问你是否存在 p , q p,q p,q 满足 A = p ( p + 1 ) 2 + q ( q + 1 ) 2 A = \frac {p(p+1)}{2}+\frac{q(q+1)}{2} A=2p(p+1)+2q(q+1)
依旧是遍历枚举 p p p,然后二分查找 q q q
AC代码:

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n;
    while(~scanf("%d", &n)) {
        int flag = 0;
        for(int i = 1; i < sqrt(2*n); ++i) {
            int p = i * (i+1) / 2;
            int lf = i, rg = sqrt(2*n), mid = (lf + rg)/2;
            while(lf <= rg) {
                int q = mid * (mid+1) / 2;
                if(p+q < n) lf = mid+1;
                else if(p+q > n)    rg = mid-1;
                else {
                    flag = 1;
                    break;
                }
                mid = (lf + rg) / 2;
            }
            if(flag == 1) break;
        }
        if(flag == 1) cout << "YES" << '\n';
        else    cout << "NO" << '\n';
    }
    return 0;
}

J - Stairs and Elevators

首先,每个查询我们可以使用不超过一个楼梯或电梯。实际上,最佳路径始终是水平的几个部分,然后是电梯或楼梯,然后是水平的几个部分。
然后,我们总是可以使用最近的楼梯/电梯之一来开始/结束。因此,我们可以按照楼梯/电梯的顺序进行二分搜索以找到最佳的,并选择使用一个楼梯或电梯。不要忘记不必到达任何楼梯/电梯的情况。
AC代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5+10;
int a[maxn], b[maxn];

int main()
{
    int x, y, n, m, v;
    cin >> x >> y >> n >> m >> v;
    for (int i = 0; i < n; i++) scanf("%d", &a[i]);
    for (int i = 0; i < m; i++) scanf("%d", &b[i]);
    int q;
    cin >> q;
    while (q--) {
        int x1, x2, y1, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if (y2 < y1)    swap(y1, y2);
        int c = lower_bound(a, a + n, y1) - a;
        int ans = (int)1e9;
        if (x1 == x2)   ans = y2 - y1;
        if (c < n)
            ans = min(ans, abs(a[c] - y1) + abs(a[c] - y2) + abs(x1 - x2));
        if (c > 0) {
            c--;
            ans = min(ans, abs(a[c] - y1) + abs(a[c] - y2) + abs(x1 - x2));
        }
        c = lower_bound(b, b + m, y2) - b;
        if (c < m) {
            ans = min(ans, abs(b[c] - y1) + abs(b[c] - y2) + (abs(x1 - x2) + v - 1) / v);
        }
        if (c > 0) {
            c--;
            ans = min(ans, abs(b[c] - y1) + abs(b[c] - y2) + (abs(x1 - x2) + v - 1) / v);
        }
        cout << ans << "\n";
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值