1. 程式人生 > 其它 >acwing第80場周賽

acwing第80場周賽

比賽地址
核心思路:這是一眼暴力搜尋題,但是我們怎麼取構造他們的引數呢。首先我們肯定需要4和7的個數,所以這兩個引數是肯定需要的,還有就是我們需要他們兩個個數加起來不能夠大於我們的目標字串的長度,所以我們也需要一個u。在然後加入我們的搜尋的字串就好了。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
char s[N];
string ans, num;
void dfs(string str, int u, int s4, int s7)//這裡的u表示遍歷到第幾層了
{
	if (u == num.size())
	{
		if (str >= num && (ans.empty() || ans > str))
			ans = str;
		return;
	}
	if (s4 < num.size()  /2)//注意這裡是不可以取等號的,還加一就不平衡了
	{
		dfs(str + '4', u + 1, s4 + 1, s7);
	}
	if (s7 < num.size() / 2)
		dfs(str + '7', u + 1, s4, s7 + 1);
}
int main()
{
cin >> num;

    if (num.size() % 2) num = '0' + num;

    dfs("", 0, 0, 0);

    if (ans.empty())
    {
        num = "00" + num;//注意我們這裡是往字串前面加0.例如9999
        dfs("", 0, 0, 0);
    }

    cout << ans << endl;

    return 0;
}

核心思路:剛開始我以為是組合數問題,沒想到居然是dp問題。

  1. 集合定義:dp[i][j][k][u]為擺放了i個白子,j個黑子,最後一段連續的黑子數目k和連續的白字數目是u。

  2. 集合劃分:其實我們可以發現這個集合不太好劃分,所以我們就需要想怎麼去轉移呢。因為dp問題其實是可以看作最短路的。所以我們需要注意我們這個狀態可以轉移到什麼其他狀態就可以了。

  3. 狀態轉移方程:dp[i+1][j][k+1][0]+=dp[i][j][k][u].

dp[i][j+1][0][u+1]+=dp[i][j][k][u].

程式碼:

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

const int N = 110, M = 11, MOD = 1e8;

int n1, n2, k1, k2;
int f[N][N][M][M];
int main()
{
	cin >> n1 >> n2 >> k1 >> k2;
	f[0][0][0][0] = 1;//不擺放也是一種方案.
	for(int i=0;i<=n1;i++)
		for(int j=0;j<=n2;j++)
			for(int k=0;k<=k1;k++)
				for (int u = 0;u <= k2;u++)
				{
					int v = f[i][j][k][u];
					if (i + 1 <= n1 && k + 1 <= k1)
						f[i + 1][j][k + 1][0] = (f[i + 1][j][k + 1][0] + v) % MOD;//為什麼是0呢,一定要注意我們的那個定義
					if (j + 1 <= n2 && u + 1 <= k2)
						f[i][j + 1][0][u + 1] = (f[i][j + 1][0][u + 1] + v) % MOD;
				}
	int res = 0;
	for (int i = 0;i <= k1;i++)
		for (int j = 0;j <= k2;j++)
			res = (res + f[n1][n2][i][j]) % MOD;
	cout << res << endl;

}