//https://img2018.cnblogs.com/blog/1646268/201908/1646268-20190806114008215-138720377.jpg

2023.7.2牛客

2023.7.2 牛客

T1

很简单的模拟,需要注意前 \(3n\) 行都是前 \(n\) 个和后 \(n\) 个是 *,其他的都是 .,然后后 \(n\) 行的话,我们发现每一行两边多一个 .,也就是之前的 * 都往中间靠一列。

code:

#include <bits/stdc++.h>

#define int long long
#define N 1010

using namespace std;
int n;
char s[N][N];

signed main()
{
	cin >> n;
	int m = n * 4;
	for(int i = 1; i <= m; i ++)
	{
		for(int j = 1; j <= m; j ++)
		{
			if(i <= m - n)
			{
				if(j > n && j <= m - n) s[i][j] = '.';
				else s[i][j] = '*';
			}
			else
			{
				int o = i - 3 * n + 1;
				if((j < o + n && j >= o) || (j <= m - o + 1 && j > m - o - n + 1)) s[i][j] = '*';
				else s[i][j] = '.';
			}
		}
	}
	for(int i = 1; i <= m; i ++)
	{
		for(int j = 1; j <= m; j ++)
			cout << s[i][j];
		cout << endl;
	}
	return 0;
}

T2

我们首先发现值域有点大,需要离散化一下。

所以我们使用两个 map 存当前值为 \(x\) 颜色为蓝或红的数量来达到同样的效果。

我们首先都存起来,然后在输入颜色的时候,如果当前是蓝色就往答案里面加上当前值为红色的元素的个数,反之加入红色。

最后我们发现每一对统计了两遍,除以二即可。


#include <bits/stdc++.h>

#define int long long
#define N 2001000

using namespace std;

int n, a[N], ans;
char s[N];
map<int, int> mpa, mpb;

signed main()
{
	cin >> n;
	for(int i = 1; i <= n; i ++) cin >> a[i];
	for(int i = 1; i <= n; i ++)
	{
		cin >> s[i];
		if(s[i] == 'B') mpb[a[i]] ++;
		else mpa[a[i]] ++;
	}
	for(int i = 1; i <= n; i ++)
	{
		if(s[i] == 'B') ans += mpa[a[i]];
		else ans += mpb[a[i]];
	}
	cout << ans / 2 << endl;
	return 0;
}

T3

我们可以发现题目里说一定有解,而字符只有两种,所以 \(01\) 的数量相差最多为 \(1\)

然后我们就可以根据这个来分情况解决,一种是两个一样多,那就 10101010,这个情况也可以 01010101,所以我们两个都要计算一下,然后取 min

然后就是一个多一个少,就是 1010101 或者 0101010

code:

#include <bits/stdc++.h>

#define int long long
#define N 200010

using namespace std;

int n, cnt1, num[N];
char s[N];

inline void solve1()
{
    int ans = 0, pos = 1;
    for(int i = 1; i <= n; i ++)
        if(num[i] == 1) ans += abs(i - pos), pos += 2;
    cout << ans << endl;
    return ;
}

inline void solve2()
{
    int ans = 0, pos = 2;
    for(int i = 1; i <= n; i ++)
        if(num[i] == 1) ans += abs(i - pos), pos += 2;
    cout << ans << endl;
    return ;
}

inline void solve3()
{
    int ans1 = 0, ans2 = 0, pos = 1;
    for(int i = 1; i <= n; i ++)
        if(num[i] == 1) ans1 += abs(i - pos), pos += 2;
    pos = 2;
    for(int i = 1; i <= n; ++ i)
		if(num[i] == 1) ans2 += abs(i - pos), pos += 2;
    cout << min(ans1, ans2) << endl;
    return ;
}

signed main()
{
    scanf("%s", s + 1);
    n = strlen(s + 1);
    cnt1 = 0;
    for(int i = 1; i <= n; i ++)
	{
        num[i] = s[i] - '0';
        cnt1 += (num[i] == 1);
    }
    if(n % 2 == 1)
	{
        if(cnt1 > n - cnt1) solve1();
        else solve2();
    }
    else solve3();
    return 0;
}

T4

一开始考虑数位 dp,但是数据范围过大,而且可以不连续,所以考虑计数 dp。

我们发现可以根据模 \(9\) 的余数来判断一个子序列是否是 \(9\) 的倍数,所以分两种情况:

  1. 当前点不选,也就是 \(0\),那我们就直接加上前一个点的即可。

  2. 当前点选,那么我们就和之前 \(9\) 的余数组成一个两位数去取模,然后累加上去。

我们最后可以发现最后答案就是长度为序列长度,并且余数为 \(0\) 的个数。

code:

#include <bits/stdc++.h>

#define int long long
#define P 1000000007
#define N 200100

using namespace std;

char s[N];
int dp[N][10], ans;

signed main()
{
    scanf("%s", s + 1);
    int n = strlen(s + 1);
    dp[0][0] = 1;
    for(int i = 1; i <= n; i ++)
	{
        for(int j = 0; j < 9; j ++)
		{
            dp[i][j] += dp[i - 1][j]; //当前位填0 
            dp[i][(j * 10 + s[i] - '0') % 9] += dp[i - 1][j];//选当前数加上前面转移过来的方案数 
            dp[i][j] %= P;//取模 
            dp[i][(j * 10 + s[i] - '0') % 9] %= P;
        }
    }
    ans = (dp[n][0] - 1 + P) % P;
    cout << ans << endl;
    return 0;
}

posted @ 2023-07-02 22:19  北烛青澜  阅读(14)  评论(0)    收藏  举报