1. 程式人生 > 其它 >Codeforces Round #742 A - D

Codeforces Round #742 A - D

A - Domino Disaster

思路:
碰到\(U\)輸出\(D\),\(L,R\)就輸出\(L,R\)

B - MEXor Mixup

思路:
做個字首異或和,細節判斷一下幾種情況即可,注意求出來的答案如果\(=a\),那麼不能用這個數,否則\(MEX\)就不是\(a\),給字首和和\(b\)加個值,用這個兩個數即可完成構造。

C - Carrying Conundrum

題意:
一個人再進行豎式加法的時候,進位的時候,把當前位置\(i\)的進位加到了\(i+2\)上而不是\(i+1\),數位從右往左依次增大。
這樣他會得到一個錯誤的答案\(n\)
現在你要做的是對於一個錯誤答案\(n\)

,給出有多少對的\((x,y),(x>0,y>0)\)滿足\(x+y\)在這種錯誤的方法下等於\(n\)

思路1:
既然這個人把加法的進位加到了左邊第二個位置,在這種情況下,可以保證如果只考慮形如\(i,i+2,i+4\)這些位置的數,那麼他的加法就是符合我們正常邏輯的加法,那麼可以相到,把\(n\)每隔一位的分成兩個數,這樣這兩個數是獨立的滿足加法的,此時我們找到兩組\((x,y) = n_1,(z,w) = n_2\),並且把\(x,z\)在十進位制,按照我們拆分的方式補回去,\(y,w\)同理,會發現此時新行成的這兩個數按照錯誤的加法相加就是的一組合法的答案。

即進位只會影響相隔一位的數,所以相鄰的數是可以獨立考慮的。

那麼一個數\(x\)有多少種方法能夠相加\(=x\),顯然是\(x+1\)種,\((n_1+1)(n_2+1)\)就是我們全部的答案,但是因為每個方案中都會涉及\(0\),那麼當兩個數的\(0\)湊到一起時還是\(0\),所以要減去這種情況的次數,\(-2\)

分開考慮的思路比較巧妙。

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e5 + 10;
int n;
char s[100];
//既然進位影響的是後兩位 那麼如果分別考慮兩個部分的話 他們是獨立的不會相互影響的 所以只要分開考慮最後一乘即可
void solve() {
	scanf("%s",s+1);
	n = strlen(s+1);
	ll a = 0,b = 0;
	for(int i = 1;i <= n;i ++) {
		if(i & 1) a = a * 10 + s[i] - '0';
		else b = b * 10 + s[i] - '0'; 
	}
	printf("%lld\n",(a + 1) * (b + 1) - 2);
}

int main() {
	int T;scanf("%d",&T);
	while(T--) solve();
	return 0;
}

思路2:
既然想計算方法數,考慮能否\(dp\)做,令\(f_{i,j,k}\)表示,能夠形成數\(n\)十進位制下的前\(i\)位,且從低位進位獲得了\(j\),並且當前這一位\(i\)對高位產生了\(k\)的進位,注意這裡的低位和高位位考慮都是相鄰的。

列舉在第\(i\)位上相加的兩位數\(x,y\),位置\(i+1\)(倒序)的低位進位\(fromlowbit\),高位進位\(tohighbit\),假如\(x + y + fromlowbit == s[i] - '0'\)即可轉移,這裡為什麼是\(+fromlowbit\),別忘了這種錯誤的加法是考慮是相隔一位,而我們記錄的是相鄰

轉移方程:
\(f[i][tohigh][(fromlowbit+x+y)/10] += f[i+1][fromlowbit][tohigh]\)

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
int n;
char s[20];
ll f[20][2][2];

void solve() {
	for(int i = 0;i <= 10;i ++) {
		for(int j = 0;j < 2;j ++) {
			for(int k = 0;k < 2;k ++) {
				f[i][j][k] = 0;
			}
		}
	}
	scanf("%s",s+1);
	n = strlen(s+1);
	for(int x = 0;x < 10;x ++) {//預處理最低位
		for(int y = 0;y < 10;y ++) {
			if((x + y) % 10 == s[n] - '0') {
				if(x + y >= 10) f[n][0][1]++;
				else f[n][0][0]++;
			}
		}
	}
	for(int i = n - 1;i >= 1;i --) {//存的是i-1的進位結果
		for(int x = 0;x < 10;x ++) {
			for(int y = 0;y < 10;y ++) {
				for(int tohigh = 0;tohigh < 2;tohigh ++) {
					for(int fromlow = 0;fromlow < 2;fromlow ++) {
						if(((x + y + fromlow) % 10) == (s[i] - '0')) {
							f[i][tohigh][(x + y + fromlow) / 10] += f[i+1][fromlow][tohigh];
						}
					}
				}
			}
		}
	}
	//顯然前兩位都不能有進位 所以答案是[1][0][0] 而沒有[1][0][1]
	printf("%lld\n",f[1][0][0] - 2);
}

int main() {
	int T;scanf("%d",&T);
	while(T--) solve();
	return 0;
}

其實這個\(dp\)狀態也可以寫成\(f_{i,j}\),表示到第\(i\)位,且向後兩位進位\(j\)的方法數
轉移方程:
\(f[i][(x+y+j)/10] += f[i+2][j]\)
但是這樣最後知識獨立的算出了最後第一位和第二位的方案數,兩個再相乘\(-2\)也即為答案,這樣就類似於思路1了,也是獨立考慮兩個部分嘛。
思路簡單就不貼程式碼了,上面\(dp\)少寫一維變一下就好了。

D - Expression Evaluation Error

題意:
給你\(s\)\(n\),現在讓你寫下\(n\)個數使其在十進位制表示下的和為\(s\),並且使得這個\(n\)個數在十一進製表示下儘可能的大,對於每組\(s\)\(n\)請輸入一種滿足最大值的合法方案。

思路:
\(x_{10}->y_{11}\),如果我們能\(y = x\),如果這個是可行的,那麼顯然就是我們能做到的最優解,例如:\(97_{10}\ ->\ 97_{11}\),為了達到這種可能,我們就要儘可能的使的最高位不會因為進位而損失,如果必須損失,讓更低的位承擔這個損失。

儘量保持十進位制下的高位,那麼就用\(10^k(k\in[1,9])\)去構造,因為還有\(n\)的限制,所以我們肯定是在儘可能的情況多去用\(10\)的冪次構造,構造的同時注意一下邊界情況的判斷,即\(s - 10^k \ge n - 1\),保證一定能構造出來\(n\)個數。

#include <bits/stdc++.h>

using namespace std;

#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
int n,s;
int ksm(int a,int b) {
	int res = 1;
	while(b) {
		if(b&1) res = res * a;
		a = a * a;
		b >>= 1;
	}
	return res;
}
void solve() {
	scanf("%d%d",&s,&n);
	if(n == 1) { 
		printf("%d\n",s);
		return ;
	}
	int x = 9;
	for(int i = 9;i >= 1;i --) {
		// cout << ksm(10,i) << '\n';
		while(s >= ksm(10,i) && n != 1 && s >= ksm(10,i) + n - 1) {
			printf("%d ",ksm(10,i));
			s -= ksm(10,i);
			n--;
		}
	}
	// cout << s << ' ' << n << "***\n";
	for(int i = 1;i < n;i ++) {
		printf("%d ",s / n);
	}
	printf("%d\n",s - (s / n) * (n - 1));
}

int main() {
	int T;scanf("%d",&T);
	while(T--) solve();
	return 0;
}