cccc-第四次训练

7-14 至多删三个字符 (35 分)

题意:

给定一串字符串 至多可以删3个字符 求最多能形成多少个的不同字符串

思路:

dp dp[i][j]代表前i个字符删掉j个 至多能形成多少个不同的字符串 

转移方程 : dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j] 

还要查重一下 如果相邻且相等删掉哪一个都形成相同的字符串 -> dp[i][j] = dp[i][j] - dp[k - 1][j - (i - k)];

#include <bits/stdc++.h> 
#include <queue>
#define ll long long
#define pi acos(-1)
#define FF ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f;
ll n, m, nn[105], nu[105];
ll ans, maxx, dp[N][4];
int tot;
string s;

void solve(){
    cin >> s;
    //d[i][j] 代表 前i个字符删掉j个字符不同字符串的个数 
    dp[0][0] = 1;
    for(int i = 1; i < s.size(); i++){
        for(int j = 0; j <= 3; j++){
            //取了j个 且取了第i个字符
            if(j > 0) dp[i][j] += dp[i - 1][j - 1];
            //取了j个 不取第i个字符
            dp[i][j] += dp[i - 1][j];
            //查重 再j范围内如果有重复 第k + 1个到第i - 1个都是删掉的 这样才能保证值相邻相同从而重复所以前k-1个就删了j-(i-k)个 
            for(int k = i - 1; k >= i - j && k > 0; k--){
                //j范围内有重复值 
                if(s[i - 1] == s[k - 1]){
                    dp[i][j] -= dp[k - 1][j - (i - k)];
                    break;
                } 
            }
        }
    }
    //删的个数不同情况情况的和即答案
    cout << dp[s.size()][3] + dp[s.size()][2] + dp[s.size()][1] + dp[s.size()][0] << "\n";
}

int main()  
{
    FF; 
    int t = 1;
    //cin >> t;
    while(t --){
        solve();
    }
    return 0; 
}

 

7-10 小字辈 (25 分)

题意:

找最晚辈分 和 最晚辈的人的编号

思路:

dfs实现 

#include <bits/stdc++.h> 
#include <queue>
#define ll long long
#define pi acos(-1)
#define FF ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n, x, a[100005], mx, vis[N], b[N];
vector<int>g[100005];
vector<int>fa[100005];
queue<int>q;
//bfs实现
void bfs(int ff){
    b[ff] = 1;
    q.push(ff);
    while(!q.empty()){
        int now = q.front();
        q.pop();
        if(vis[now]) continue;
        vis[now] = 1;
        for(int i = 0; i < g[now].size(); i++){
            int son = g[now][i];
            //儿子辈分比父亲辈分+1
            b[son] = b[now] + 1;
            fa[b[son]].push_back(son);
            //记录最晚的辈分
            mx = max(b[son], mx);
            if(!vis[son]) q.push(son);
        }
    }
}

void solve(){
    mx = 1;//注意最高辈分是1 从1开始(不是0,不然只有一个辈分时会输出0就错了)
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> x;
        //fa[1]储存最早的祖先
        if(x == -1) {
            fa[1].push_back(i);
            continue;
        }
        g[x].push_back(i);
    }
    //从祖先开始遍历
    for(int i = 0; i < fa[1].size(); i++){
        bfs(fa[1][i]);
    }
    cout << mx << "\n";
    //排序 
    sort(fa[mx].begin(), fa[mx].end());
    //最晚辈的人
    for(int i = 0; i < fa[mx].size(); i++){
        cout << fa[mx][i] << " \n"[i == fa[mx].size() - 1];
    }
}

int main()  
{
    FF; 
    int t = 1;
    //cin >> t;
    while(t --){
        solve();
    }
    return 0; 
}

 

7-9 分而治之 (25 分)

题意:给你几个方案 删去几个点 判断这个方案能否让每个点的入度都变为0

#include <bits/stdc++.h> 
#include <queue>
#define ll long long
#define pi acos(-1)
#define FF ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;
int n, m, x, y, a[100005], mx, cnt[N], b[N];
vector<int>g[100005];
vector<int>fa[100005];
queue<int>q;

void solve(){
    cin >> n >> m;
    //存图 
    for(int i = 1; i <= m; i++){
        cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    int q;
    cin >> q;
    while(q--){
        //cnt代表每个点的入度 
        for(int i = 1; i <= n; i++){
            cnt[i] = g[i].size();
        }
        int s, now;
        cin >> s;
        int flag = 1;
        while(s --){
            cin >> now;
            cnt[now] = 0;
            //对于每个方案的一个数 每次删去这个点 那与他相接的点的入度都减1
            for(int i = 0; i < g[now].size(); i++){
                int to = g[now][i];
                cnt[to]--;
            }
        }
        //最后判断是否每个点都没有入度了 
        for(int i = 1; i <= n; i++){
                if(cnt[i] > 0) {
                    flag = 0;
                    break;
                }
            }
        if(!flag) cout << "NO\n";
        else cout << "YES\n";
    }
}

int main()  
{
    FF; 
    int t = 1;
    //cin >> t;
    while(t --){
        solve();
    }
    return 0; 
}

 

7-2 倒数第N个字符串 (15 分)

题意:

规定字符串长度为n 从aa..(长n) 到 zz.. 求倒数第k个字符串 (从左到右按字典序进行)

思路:

因为是倒数 所以可以直接把zz..看成开头正数k个就可以了 

思路就是哈希 以26为进制 z-a分别对应数字0-25

#include <bits/stdc++.h> 
#include <queue>
#define ll long long
#define pi acos(-1)
#define FF ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;
ll n, m, b[N];
ll ans, maxx, a[101][101];
map<char, int>mp;
map<int , char>pm;
char ch, ch1;
ll nn[10];

void solve(){
    cin >> n >> m;
    int num = -1;
    //因为是倒数 所以从z开始 z - a代表数字0-25
    for(char i = 'z'; i >= 'a'; i--){
        //数字和字母先预处理一一对应一下
        mp[i] = ++num;
        pm[num] = i;
    }
    ll x = 0;
    //从zz..开始 所以每个位上的数字为0 nn[i]代表第几位 
    for(int i = 1; i <= n; i++){
        nn[i] = 0;
    }
    m--;//第一个数是0 不是1开始 所以m要先减1
    for(int i = 1; i <= n && m; i++){
        nn[i] += m % 26;//把m换成26进制加给原数
        //简单模拟进位
        if(nn[i] >= 26) {
            nn[i] %= 26;
            nn[i + 1] += nn[i] / 26;
        }
        m /= 26;
    }
    //最后答案换成字符输出即可
    for(int i = n; i >= 1; i--){
        cout << pm[nn[i]];
        x /= 26;
    }
}

int main()  
{
    FF; 
    int t = 1;
    //cin >> t;
    while(t --){
        solve();
    }
    return 0; 
}

 

7-1 天梯赛座位分配 (20 分)

题意:

天梯赛每年有大量参赛队员,要保证同一所学校的所有队员都不能相邻,分配座位就成为一件比较麻烦的事情。为此我们制定如下策略:假设某赛场有 N 所学校参赛,第 i 所学校有 M[i] 支队伍,每队 10 位参赛选手。令每校选手排成一列纵队,第 i+1 队的选手排在第 i 队选手之后。从第 1 所学校开始,各校的第 1 位队员顺次入座,然后是各校的第 2 位队员…… 以此类推。如果最后只剩下 1 所学校的队伍还没有分配座位,则需要安排他们的队员隔位就坐。本题就要求你编写程序,自动为各校生成队员的座位号,从 1 开始编号。

输入格式:

输入在一行中给出参赛的高校数 N (不超过100的正整数);第二行给出 N 个不超过10的正整数,其中第 i 个数对应第 i 所高校的参赛队伍数,数字间以空格分隔。

输出格式:

从第 1 所高校的第 1 支队伍开始,顺次输出队员的座位号。每队占一行,座位号间以 1 个空格分隔,行首尾不得有多余空格。另外,每所高校的第一行按“#X”输出该校的编号X,从 1 开始。

思路:

看代码

#include <bits/stdc++.h> 
#include <queue>
#define ll long long
#define pi acos(-1)
#define FF ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int inf = 0x3f3f3f3f;
ll n, m, nn[105], nu[105];
ll ans, maxx, a[15][15][105];
int tot;
string na;

double abss(double a, double b){
    if(a > b) return a - b;
    else return b - a;
}

struct node {
    string name;
    int num;
}people[10005];

void solve(){
    cin >> n;
    ll mx = 0;
    int mm;
    //每个学校有几个队 mx记录最多队伍的数量
    for(int i = 1; i <= n; i++){
        cin >> nn[i];
        //nu复制每个学校的队伍数 供后续处理 
        nu[i] = nn[i];
        if(nn[i] > mx){
            mx = nn[i];
            //mm记录最多队伍的那个学校的编号
            mm = i;
        }
    }
    int cnt = 0//记录最多队伍的学校有几个
    for(int i = 1; i <= n; i++){
        if(nn[i] == mx) cnt++;
    }
    //模拟安排座位 
    //a[i][j][k]其中i代表第几个对 j代表第几个人 k代表第几个学校 
    for(int i = 1; i <= mx; i++){
        for(int j = 1; j <= 10; j++){
            for(int k = 1; k <= n; k++){
                if(nn[k] < i) continue;//如果队伍不够 就继续 排后面的学校的人 
                a[i][j][k] = ++ tot;
            }
        }
    }
    //找到第二多的队伍数 用se标记他学校的编号 
    sort(nu + 1, nu + n + 1);
    int se;
    for(int i = 1; i <= n; i++){
        if(nn[i] == nu[n - 1]) se = i;
    }
    //如果最多的队伍的学校不止一个那么 最后多余的人要隔两个位子坐
    if(cnt < 2){
        //还要判断一下除去多余的人 最后一个人排到的是否为最多那个学校的人 如果是第一个多余的人与前面的人也要隔两个位置否则隔一个
        int xx = nu[n - 1] + 1;//从恰好排完的下一队 开始排多余的 
        int bh = a[xx][1][mm] - 2;//以为之后多余的统一要+2 这里先减2
        //如果第二大的队伍数的学校在最多队伍数学校的前面 说明恰好排完的最后一个也是队伍数最多的那个学校的人 那么多余的第一个人也要多隔一位
        if(se < mm) {
            bh ++;
        }
        for(int j = xx; j <= mx; j++){
            for(int i = 1; i <= 10; i++){
                a[j][i][mm] = bh + 2;
                bh += 2;
            }
        }
        
    }
    按顺序输出即可 
    for(int i = 1; i <= n; i++){
        cout << "#" << i << "\n";
        for(int j = 1; j <= nn[i]; j++){
            for(int k = 1; k <= 10; k++){
                cout << a[j][k][i] << " \n"[k == 10];
            }
        }
    }
    
}

int main()  
{
    FF; 
    int t = 1;
    //cin >> t;
    while(t --){
        solve();
    }
    return 0; 
}

 

posted @ 2022-03-18 21:18  Yaqu  阅读(215)  评论(0)    收藏  举报