AtCoder Beginner Contest 357

AtCoder Beginner Contest 357

C - Sierpinski carpet BFS

Problem Statement

For a non-negative integer \(K\), we define a level-\(K\) carpet as follows:

  • A level-\(0\) carpet is a \(1 \times 1\) grid consisting of a single black cell.
  • For \(K \gt 0\), a level-\(K\) carpet is a \(3^K \times 3^K\) grid. When this grid is divided into nine \(3^{K-1} \times 3^{K-1}\) blocks:
    • The central block consists entirely of white cells.
    • The other eight blocks are level-\((K-1)\) carpets.

You are given a non-negative integer \(N\).
Print a level-\(N\)​ carpet according to the specified format.

问题陈述

对于一个非负整数 \(K\) ,我们定义一个等级地毯 \(K\) 如下:

  • 一级- \(0\) 地毯是由一个黑色单元格组成的 \(1 \times 1\) 网格。
  • 对于 \(K \gt 0\) 来说, \(K\) 级地毯是一个 \(3^K \times 3^K\) 网格。当这个网格被划分为九个 \(3^{K-1} \times 3^{K-1}\) 块时:
    • 中央区块完全由白色单元格组成。
    • 其他八个区块是 \((K-1)\) 级地毯。

给你一个非负整数 \(N\)
请按照指定格式打印 \(N\)​ 级地毯。

Constraints

  • \(0 \leq N \leq 6\)
  • \(N\)​ is an integer.

Output

Print \(3^N\) lines.
The \(i\)-th line (\(1 \leq i \leq 3^N\)) should contain a string \(S_i\) of length \(3^N\) consisting of . and #.
The \(j\)-th character of \(S_i\) (\(1 \leq j \leq 3^N\)) should be # if the cell at the \(i\)-th row from the top and \(j\)-th column from the left of a level-\(N\)​ carpet is black, and . if it is white.

Sample Output 1

###
#.#
###

A level-\(1\) carpet is a \(3 \times 3\) grid as follows:

When output according to the specified format, it looks like the sample output.

Solution

对于一个N级地毯,由题我们可以将其分成九个小块,每个小块为\(3^{N-1} \times 3^{N-1}\) ,中心块固定全为.,周围的八个小块,每一块都是由N-1级地毯构成,那一个N-1级地毯又可以分成八个N-2级地毯和一个全为.的中心块,就这么对每一子块划分下去,最后会划分到1级地毯,他的八个子块为0级地毯也就是八个#,一个中心块.,至此就划分完毕。

很明显我们使用递归的方法做,不断划分子块,直到其为0级。递归处理的每一层我们要先对当前块的中心块做处理,然后再向下搜索其它八个子块。

利用矩阵存储,对每个子块用其左上角坐标搜索,方便找他的中心块

Code
#include<bits/stdc++.h>
#define int long long

using namespace std;

char g[800][800]; //存答案矩阵
int a[10];  //a[0]~a[n] 存3的0~n次幂的结果
int n;

void dfs(int u, int x, int y)
{
    if(u == 0) return; //u=0时只有一个点 为# 不用改

    //对一个大块来说,将其分为九个小块,中间的块全变为'.',其余周围八块继续向下搜索

    //对当前搜到的块 将其中心块全部改成'.' ,分成的八个小块的长和宽均为a[u - 1],中心宽的左上角坐标为(x + a[u - 1], y + a[u - 1])
    for (int i = x + a[u - 1]; i < x + a[u - 1] * 2; i ++ )
        for (int j = y + a[u - 1]; j < y + a[u - 1] * 2; j ++ )
        {
            g[i][j] = '.';
        }

    //搜其余八个小块,利用其左上角坐标向下搜索
    for (int i = 0; i < 3; i ++ )
        for (int j = 0; j < 3; j ++ )
        {
            if (i == 1 && j == 1) continue; //中心块的情况,上面已经处理过了,跳过
            dfs(u - 1, x + i * a[u - 1], y + j * a[u - 1]); //用子块的左上角坐标,向下搜每个子块的情况
        }
}

void solve()
{
    cin >> n;

    a[0] = 1;
    for(int i = 1; i <= 6; i ++ ) a[i] = a[i - 1] * 3;

    //先将答案矩阵内所有位置置为'#',后面我们就只需对其中数量较少的'.'做更改
    for (int i = 0; i < a[n]; i ++ )
    {
        for (int j = 0; j < a[n]; j ++ )
        {
            g[i][j] = '#';
        }
    }

    //对其中'.'的部分进行更改
    dfs(n, 0, 0);

    //输出答案
    for (int i = 0; i < a[n]; i ++ )
    {
        for (int j = 0; j < a[n]; j ++ )
        {
            cout << g[i][j];
        }
        cout << endl;
    }

    return;

}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    
    solve();

    return 0;
}

D - 88888888 数论

Problem Statement

For a positive integer \(N\), let \(V_N\) be the integer formed by concatenating \(N\) exactly \(N\) times.
More precisely, consider \(N\) as a string, concatenate \(N\) copies of it, and treat the result as an integer to get \(V_N\).
For example, \(V_3=333\) and \(V_{10}=10101010101010101010\).

Find the remainder when \(V_N\) is divided by \(998244353\).

问题陈述

对于正整数 \(N\) ,设 \(V_N\) 是由 \(N\) 恰好连接 \(N\) 次所组成的整数。
更确切地说,把 \(N\) 看作一个字符串,连接它的 \(N\) 份,并把结果看作一个整数,得到 \(V_N\)
例如, \(V_3=333\)\(V_{10}=10101010101010101010\)

\(V_N\) 除以 \(998244353\)​ 的余数。

Constraints

  • \(1 \leq N \leq 10^{18}\)
  • \(N\) is an integer.

Sample Input 2

9

Sample Output 2

1755646

The remainder when \(V_9=999999999\) is divided by \(998244353\) is \(1755646\).

Solution

\(V_N\) 是由 \(N\) 恰好连接 \(N\) 次所组成的整数,例如\(V_9=999999999\),其实我们可以发现可以变成\(V_9 = 9*10^0 + 9*10^1 + ... + 9*10^9\),然后我们把9提出来里面其实是一个等比数列\(V_9=9*(1 + 10 + 100 + ... +10^9)=9* a_1\frac{1-q^n}{1-q} = 9*\frac{10^9-1}{9}\)

推广到一般情况

\(V_n=n*\frac{10^n-1}{9}\)

注意此时我们只写出了N只有1位的情况

如果是\(V_{10}=10101010101010101010\)该怎么表示呢 其实就是把高位1和低位0捆起来,一起前进,每一位都直接前进两位

\(V_{10}=10 + 10*10^{2*1} + 10*10^{2*2}+...10*10^{2*8}\)

推广到一般形式 k为N的位数

\(V_N=N+N*10^{k*1}+N*10^{k*2}...+N*10^{k*(N-1)}\)

N提出来

\(V_N=N*(1+10^{k*1}+...+10^{k*(N-1)})=N* \frac{10^{k*N}-1}{10^k-1}\)

公式推导完成,由于本题要模上\(998244353\)​ 我们采用乘法逆元计算除法

用快速幂求\(10^{kN}\)

---悲伤分割线

code一直通不过 一直WA+TLE

原因就在这串代码 这里是算\(N*(10^{k*N}-1)\)

 ans = t * (qmi(qmi(10, k), n) - 1) % mod;

这里刚开始写成t * (10, k * n) - 1) % mod 造成TLE和WA debug半天 在这种数据很大的题内对乘法一定要小心再小心 一不小心就会狠狠溢出

TLE的原因是快速幂内有一个while循环 k * n数据过大循环次数过多 就TLE了 WA原因也出在这里 k * n 可能溢出了(还是longlong范围 想想得多吓人) 我们需要将10^{k*n}拆开写成qmi(qmi(10, k), n) 做两次快速幂 这样就不会超时 在qmi()内也有取模也不会WA

总结两条经验

  • 数据很大的题里一定得注意随时取模 可以将步骤拆开 分开取模 最后再乘

  • 特别特别注意乘法 两个数量级都很大的数一乘很容易溢出

  •   //ans *= qmi(tmp, mod - 2) % mod; //将除法换成做乘法逆元
      ans = ans * qmi(tmp, mod - 2) % mod; //将除法换成做乘法逆元
    
  • 刚开始这行语句写成上面的形式 也溢出了 因为直接写*=就起不到对结果ans * qmi(tmp, mod - 2)取模的作用了

    • 所以以后数据很大的题 一定不要写*= 导致取模失败
Code
#include<bits/stdc++.h>
#define int long long

using namespace std;

const int mod = 998244353;

int n;
int ans;

//快速幂求幂和逆元
int qmi(int x,int k)
{
	int res = 1;
	while (k > 0)
	{
		if (k % 2) res = (res * x) % mod;
		x = (x * x) % mod;
		k = k / 2;
	}
	return res;
}

int getLen(int x)
{
    int res = 0;
    while (x > 0)
    {
        x /= 10;
        res ++ ;
    }

    return res;
}

void solve()
{
    cin >> n;
    int k = getLen(n); //找到n的位数
    int t = n % mod; //先将n取模 避免后面乘法溢出
    //cout << k << endl;
    ans = t * (qmi(qmi(10, k), n) - 1) % mod; //这里刚开始写成t * (10, k*n) - 1) % mod 造成TLE和WA 
    //cout << ans << endl;
    int tmp = (qmi(10, k) - 1) % mod;
    ans = ans * qmi(tmp, mod - 2) % mod; //将除法换成做乘法逆元
    cout << ans << endl;
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    
    solve();

    return 0;
}
posted @ 2024-06-12 17:59  MsEEi  阅读(25)  评论(0)    收藏  举报