1.Filomino 2
题目大意
给定一个 n*n 的矩阵,要求把 1 到 n 的数填进去,并满足以下条件:
- 只能填在矩阵的下三角形区
- 对于第 i 个数,要有 i 个格子都填这个数
- 填相同数的格子必须互相连通
- 主对角线所有格子的数必须不重复
数字并不一定是按1到n的顺序给出的
解题思路
贪心的思想,从最上面的对角点开始放第一个数,对与每一个数字优先往左找点放数字,如果放不下开始往下走,这样就可以保证全部放下。
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<stack>
using namespace std;
typedef unsigned long long ll;
typedef pair<ll, ll> PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
const int M = 1e6 + 10;
int a[510];
int ans[510][510];
int gcd(int a, int b){
return b ? gcd(b, a % b) : a;
}
void take(int a, int b, int c, int d){
if(!c){
return;
}
ans[a][b] = d;
if(ans[a][b - 1]==0&&(b - 1)>0){
take(a, b - 1, c - 1, d);
}
else{
take(a + 1, b, c - 1, d);
}
}
int main(){
std::ios::sync_with_stdio(false);
int n;
cin >> n;
for (int i = 1; i <= n;i++){
cin >> a[i];
}
for (int i = 1; i <= n;i++){
int tot = a[i];
int x = i, y = i;
take(x, y, tot, tot);
}
for (int i = 1; i <= n;i++){
for (int j = 1; j <= n;j++){
if(ans[i][j]==0)
continue;
cout << ans[i][j] << ' ';
}
cout << endl;
}
return 0;
}
2.Add One
题目大意
给定一个字符串,每次操作对这个字符串的每一位都加一,如果出现进位,两个数在下一次操作中看作单独的两个数,求进行 m 次操作后字符串变为多少位?
解题思路
由于每一位数之间都不会互相影响,所以我们独立的考虑每一位数,最后求解总和,用动态规划的思想,dp[i] [j]代表 i 这个数进行 j 次操作时产生的位数,由于加到10会出现进位,所以我们初始化 j 从 1 到 10 的情况,可以很容易的判断每个数的值是多少,观察可知,当 j > 10 时,就可以用之前的值来表示之后的情况了,以 9 为例
d
p
[
9
]
[
1
]
=
d
p
[
1
]
[
0
]
+
d
p
[
0
]
[
0
]
d
p
[
9
]
[
2
]
=
d
p
[
1
]
[
1
]
+
d
p
[
0
]
[
1
]
d
p
[
9
]
[
3
]
=
d
p
[
2
]
[
1
]
+
d
p
[
1
]
[
1
]
.
.
.
.
.
.
.
d
p
[
9
]
[
10
]
=
d
p
[
9
]
[
1
]
+
d
p
[
8
]
[
1
]
d
p
[
9
]
[
11
]
=
d
p
[
9
]
[
2
]
+
d
p
[
9
]
[
1
]
.
.
.
.
.
.
.
d
p
[
9
]
[
x
]
=
d
p
[
9
]
[
x
−
10
]
+
d
p
[
9
]
[
x
−
9
]
dp[9][1] = dp[1][0] + dp[0][0]\\dp[9][2]=dp[1][1]+dp[0][1]\\dp[9][3] =dp[2][1]+dp[1][1]\\.......\\dp[9][10] = dp[9][1]+dp[8][1]\\dp[9][11]=dp[9][2]+dp[9][1]\\.......\\dp[9][x] =dp[9][x-10]+dp[9][x-9]
dp[9][1]=dp[1][0]+dp[0][0]dp[9][2]=dp[1][1]+dp[0][1]dp[9][3]=dp[2][1]+dp[1][1].......dp[9][10]=dp[9][1]+dp[8][1]dp[9][11]=dp[9][2]+dp[9][1].......dp[9][x]=dp[9][x−10]+dp[9][x−9]
所以直接预处理之后求值即可
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<stack>
using namespace std;
typedef unsigned long long ll;
typedef pair<ll, ll> PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
const int M = 1e6 + 10;
int a[20];
ll dp[20][N];
void to_dp(){
for (int j = 0; j <= 9;j++){
dp[j][0] = 1;
}
for (int i = 0; i <= 9; i++)
{
for (int j = 10 - i; j <= 10;j++){
dp[i][j] = 2;
}
for (int j = 0; j < 10 - i;j++){
dp[i][j] = 1;
}
}
dp[9][10] = 3;//唯一一个特别的
for (int i = 11; i <= N - 1;i++){
for (int j = 0; j <= 9;j++){
dp[j][i] = (dp[j][i - 10] % mod + dp[j][i - 9] % mod) % mod;
}
}
}
int main(){
std::ios::sync_with_stdio(false);
int t;
cin >> t;
to_dp();
while(t--){
for (int i = 0; i <= 10;i++){
a[i] = 0;
}
int n, m;
cin >> n >> m;
while(n){
int tot = n % 10;
n /= 10;
a[tot]++;
}
ll ans = 0;
for (int i = 0; i <= 9;i++){
ans = (ans % mod + a[i] % mod * dp[i][m] % mod) % mod;
}
cout << ans << endl;
}
return 0;
}
3.Permutation by Sum
题目大意
给你 n,l,r,s,四个数要求输出一个长度为 n 的排列,且第 l 个数到第 r 个数的和为 s ,如果不行的话输出 -1
解题思路
贪心的解决问题,由于目标区间的长度已知,所以采用补数的策略,优先放最小的进去,如果已经大于 s 了直接输出 -1,若还不满 s 那么逐渐把区间里的数换成尽可能大的数,如果还完后还达不到 s 那么也输出 -1
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<stack>
using namespace std;
typedef unsigned long long ll;
typedef pair<ll, ll> PII;
const int mod = 1e9 + 7;
const int N = 2e5 + 100;
const int M = 1e6 + 10;
bool anns[510];
int main(){
std::ios::sync_with_stdio(false);
int t;
cin >> t;
while(t--){
memset(anns, 0, sizeof anns);
int n, l, r, s;
cin >> n >> l >> r >> s;
int num = r - l + 1;
vector<int> ans;
int sum = 0;
for (int i = 1; i <= num;i++){
ans.push_back(i);
sum += i;
}
if(sum > s){
cout << -1 << endl;
continue;
}
if(sum == s){
int tag = num + 1;
int tag1 = 0;
for (int i = 1; i < l;i++){
cout << tag << ' ';
tag++;
}
for (int i = l; i <= r;i++){
cout << ans[tag1] << ' ';
tag1++;
}
for (int i = r + 1; i <= n;i++){
cout << tag << ' ';
tag++;
}
cout << endl;
}
if(sum < s){
int dec = s - sum;
int tot = n;
int tot1 = ans.size() - 1;
bool cann = 1;
while(dec){
int num = tot - ans[tot1];
if(num>=dec){
ans[tot1] += dec;
dec = 0;
}
else{
dec -= num;
ans[tot1] = tot;
tot--;
tot1--;
if(tot1<0&&dec>0){
cann = 0;
break;
}
}
}
if(!cann){
cout << -1 << endl;
}
else{
for (int i = 0; i < ans.size();i++){
anns[ans[i]] = true;
}
int tt = 1;
int l1 = l - 1;
while(l1){
if(anns[tt]){
tt++;
}
else{
l1--;
cout << tt << ' ';
tt++;
}
}
for (int i = 0; i < ans.size();i++){
cout << ans[i] << ' ';
}
int r2 = n - r;
while(r2){
if(anns[tt]){
tt++;
}
else{
r2--;
cout << tt << ' ';
tt++;
}
}
cout << endl;
}
}
}
return 0;
}