codeforces 刷题2

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][x10]+dp[9][x9]
所以直接预处理之后求值即可

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值