cccc-第四次训练
题意:
给定一串字符串 至多可以删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; }
题意:
找最晚辈分 和 最晚辈的人的编号
思路:
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; }
题意:给你几个方案 删去几个点 判断这个方案能否让每个点的入度都变为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; }
题意:
规定字符串长度为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; }
题意:
天梯赛每年有大量参赛队员,要保证同一所学校的所有队员都不能相邻,分配座位就成为一件比较麻烦的事情。为此我们制定如下策略:假设某赛场有 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; }