C Carrying Conundrum(思维)
方法一
直接dfs搜索,进位与不进,时间复杂度O(2^9)。
#include <bits/stdc++.h>
#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 3e5 + 10;
const double eps = 1e-5;
int dig[15][2];
struct num {
int d[15], cnt;
num() {
cnt = 1;
d[0] = 0;
};
num(int x) {
cnt = 0;
do {
d[cnt++] = x % 10;
x /= 10;
} while(x);
}
bool sub(int p) {
while(p < cnt) {
d[p]--;
if(d[p] < 0) {
d[p] += 10;
} else break;
p += 2;
}
bool flag = p < cnt;
while(cnt > 0 && d[cnt - 1] == 0) cnt--;
return flag;
}
};
ll dfs(num x, int p) {
if(p >= x.cnt) return 1;
ll res = 0;
res = dig[x.d[p]][0] * dfs(x, p + 1);
if(!x.sub(p + 2)) return res;
res += dig[x.d[p]][1] * dfs(x, p + 1);
return res;
}
int main() {
IOS;
for(int i = 0; i <= 9; i++) {
for(int j = 0; j <= 9; j++) {
dig[(i + j) % 10][i + j >= 10]++;
}
}
int t;
cin >> t;
while(t--) {
int n;
cin >> n;
cout << dfs(num(n), 0) - 2 << endl;
}
}
方法二
一次进两位,相当于奇数位和偶数位分别拿出来相加在合并起来。故可以拆位。时间复杂度O(nlogn)
#include <bits/stdc++.h>
#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 3e5 + 10;
const double eps = 1e-5;
int d[N];
int main() {
IOS;
int t;
cin >> t;
while(t--) {
int n;
cin >> n;
int cnt = 0;
do {
d[cnt++] = n % 10;
n /= 10;
} while(n);
reverse(d, d + cnt);
int a = 0, b = 0;
for(int i = 0; i < cnt; i++) {
if(i % 2) {
a = a * 10 + d[i];
} else {
b = b * 10 + d[i];
}
}
cout << (a + 1) * (b + 1) - 2 << endl;
}
}
D Expression Evaluation Error(栈)
可以发现相加进位越少越优,故贪心拆成若干10^n即可。
#include <bits/stdc++.h>
#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 3e5 + 10;
const double eps = 1e-5;
ll st[N];
int top;
vector<ll> ans;
int main() {
IOS;
int t;
cin >> t;
while(t--) {
ans.clear();
top = 0;
ll s;
int n;
cin >> s >> n;
ll pw = 1;
while(s) {
int d = s % 10;
for(int i = 1; i <= d; i++) {
st[top++] = pw;
}
s /= 10;
pw *= 10;
}
reverse(st, st + top);
while(top < n) {
ll v = st[top - 1];
top--;
if(v == 1) {
n--;
ans.push_back(1);
} else {
for(int i = 1; i <= 10; i++) {
st[top++] = v / 10;
}
}
}
while(n > 1) {
ans.push_back(st[top - 1]);
top--;
n--;
}
ll last = 0;
for(int i = 0; i < top; i++) last += st[i];
ans.push_back(last);
for(int i = 0; i < ans.size(); i++) cout << ans[i] << "
"[i == ans.size() - 1];
}
}
E Non-Decreasing Dilemma(线段树)
我的方法麻烦了,直接一颗线段树即可完成,直接维护递增的段和答案。
// 略
F One-Four Overload(构造)
题意
给定只由'.'和'X'构成的n x m的矩阵,要求在'.'处填入1或4,使得'X'加上相邻的'.'处的值(如果没有就为0)可以被5整除。输出构造的矩阵,不存在输出“NO”。
题解
显然,如果与'X'相邻的'.'的个数如果为奇数,必无解,所以'X'必须有偶数个相邻的'.',而且相邻的1和4的个数必须相等。
等价表示就是'X'必须与偶数个'X'相邻。如果把相邻的'X'连边,可以发现'X'要么构成一个欧拉回路,要么是一个孤立的点。'X'可以把'.'分成一个个联通块,相邻联通块之间连边。
这样得到的图必定是二部图(这个还不会证明),由于在边界处相邻的联通块颜色要求不同,所以可以直接先给联通块二染色。接着按照以下方式构造:
- 奇数列填1,偶数填4,从上往下染
- 如果当前位置对应的联通块和上面最近的联通块颜色不同,则“翻转flip”填的数(1变成4,4变成1)。
这样肯定是合法的。因为相同联通块内的,满足1和4按列交替填的规律,所以孤立的'X'位于一个联通块内,必然有上下都为1(4),左右都为4(1)合法;对于边界的'X',由于“翻转“,它上下和左右相邻的'.'将位于不同相邻的联通块,所以填的数也不一样,合法;对于'L'形相邻的'.',它们位于相同的联通块,满足交替14的规律,所以填的数也不一样,合法。
注意找联通块要八个方向找。
#include <bits/stdc++.h>
#define endl '
'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 1e3 + 10;
const double eps = 1e-5;
int n, m, ind;
vector<int> np[N * N];
char arr[N][N];
int id[N][N];
int ans[N][N];
int col[N * N];
void dfs(int x, int y) {
id[x][y] = ind;
for(int i = x - 1; i <= x + 1; i++) {
for(int j = y - 1; j <= y + 1; j++) {
if(x == i && y == j || arr[i][j] == '?') continue;
if(arr[i][j] == '.' && !id[i][j]) {
dfs(i, j);
}
}
}
}
int flip(int x) {
return x == 1 ? 4 : 1;
}
int main() {
IOS;
memset(arr, '?', sizeof arr);
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> arr[i] + 1;
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(arr[i][j] == '.' && !id[i][j]) {
++ind;
dfs(i, j);
}
}
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(arr[i][j] == 'X') {
bool flag = ((arr[i - 1][j] == '.') && (arr[i + 1][j] == '.'));
if(flag && id[i - 1][j] != id[i + 1][j]) {
np[id[i - 1][j]].push_back(id[i + 1][j]);
np[id[i + 1][j]].push_back(id[i - 1][j]);
}
}
}
}
queue<int> q;
for(int i = 1; i <= ind; i++) {
if(col[i]) continue;
col[i] = 1;
q.push(i);
while(!q.empty()) {
int cur = q.front();
q.pop();
for(int nt : np[cur]) {
if(col[nt]) continue;
col[nt] = (col[cur] ^ 2);
q.push(nt);
}
}
}
for(int j = 1; j <= m; j++) {
int res = (j % 2) ? 1 : 4;
ans[1][j] = res;
int prep = col[id[1][j]];
for(int i = 2; i <= n; i++) {
if(arr[i][j] == 'X') continue;
if(prep != col[id[i][j]]) res = flip(res);
ans[i][j] = res;
prep = col[id[i][j]];
}
}
bool ok = true;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(arr[i][j] == 'X') {
int num = 0;
if(arr[i - 1][j] == '.') {ans[i][j] += ans[i - 1][j]; num++;}
if(arr[i + 1][j] == '.') {ans[i][j] += ans[i + 1][j]; num++;}
if(arr[i][j - 1] == '.') {ans[i][j] += ans[i][j - 1]; num++;}
if(arr[i][j + 1] == '.') {ans[i][j] += ans[i][j + 1]; num++;}
if(num % 2) ok = false;
}
}
}
if(ok) {
cout << "YES" << endl;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
cout << ans[i][j] << "
"[j == m];
}
}
} else {
cout << "NO" << endl;
}
}