A
增广
#include<bits/stdc++.h> using namespace std; const int MAXN = 1000000 + 10; vector<int> g[MAXN]; int a[MAXN], b[MAXN], sz[MAXN], cnt[MAXN]; bool mg[MAXN], vis[MAXN]; int n, m; bool dfs(int u, int f = -1) {if (g[u].empty()) //如果当前数没有位置是成对的(a[i+1]=a[i]+1)当然不可能缝 {return false;}//第一种情况 for (auto &p : g[u]) //枚举当前数每个成对的位置if (p != f){if (!vis[p + 1] || cnt[u + 1] == 1) //如果当前这对后面的位置没有被缝并且后面的数数量为1 {mg[p] = vis[p] = vis[p + 1] = 1; //缝起来 返回trueif (f != -1){mg[f] = 0;}return true;}}for (auto &p : g[u])if (p != f){if (dfs(u + 1, p + 1)){mg[p] = vis[p] = vis[p + 1] = 1;if (f != -1){mg[f] = 0;}return true;}}return false; } int main() {scanf("%d", &n);m = 0; //m是当前数组的数量for (int i = 0, p(-1); i < n; ++ i){int x;scanf("%d", &x);if (x == p) //p是上一个加入的数 {sz[m - 1] ++; //如果现在加入的和上一个相同就给上一个sz++ }else //不同的话 加入当前数更新p {p = x;a[m] = x;sz[m ++] = 1;}}n = m;for (int i = 0; i < n; i++){b[i] = a[i];}sort(b, b + n);for (int i = m = 0; i < n; i++) //初始化m进行离散化操作if (i == 0 || b[i] > b[m - 1]){b[m++] = b[i];}for (int i = 0; i < n; ++ i) //离散化 {a[i] = lower_bound(b, b + m, a[i]) - b;cnt[a[i]] ++; //计数 计算每种数的数量 }// for (int i = 0; i < n; i++)// {// cout << a[i] << " ";// }// cout << endl;for (int i = 0; i + 1 < n; ++ i){if (a[i] + 1 == a[i + 1]) //如果后一个是前一个+1就建一条有向边 {g[a[i]].push_back(i); //记录每一对可以缝的位置前面的哪个 }}int ret = n - 1; //答案(缩点之后缝之前的答案 这里claris姐姐写错了 应该是n-1)for (int i = m - 1; i >= 0; -- i) //从大到小尝试是否可以缝当前的数 {if (dfs(i)) //如果返回true即可以缝的话 答案减少一个 {-- ret; //对于每一种数 最多只能缝一次 所以最多-1 }}printf("%d", ret); }
B
签到题
D
模拟题
F
给你一个中序遍历 和每个点的权值 问你存不存在一颗树使得每个节点的祖先和它的权值是互质的
解:
质因数分解+分治模拟
因为中序遍历有个特点 如果一个点是一个子树的根的话 左儿子都在左边 右儿子都在右边
所以要求互质的是一段区间 用GCD来做的话肯定会超时 我们给每个合数一个leftprime表示该合数质因数分解后最小的质数
首先我们从左到右枚举 维护每个质数所到的最右边 更新每个合数的答案 再反过来从右到左做一次
然后模拟树分治找到根递归地看能不能构造树
/*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; typedef unsigned long long ull; const double eps = 1e-8; const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}}; const int mod = 1e9 + 7, gakki = 5 + 2 + 1 + 19880611 + 1e9; const int MAXN = 1e6 + 5, MAXM = 1e5 + 5; const int MAXQ = 100010; //int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1; /*inline void addedge(int u, int v, ll c) {to[++tot] = v;nxt[tot] = Head[u];cost[tot] = c;Head[u] = tot; }*/ inline void read(int &v) {v = 0;char c = 0;int p = 1;while (c < '0' || c > '9'){if (c == '-'){p = -1;}c = getchar();}while (c >= '0' && c <= '9'){v = (v << 3) + (v << 1) + c - '0';c = getchar();}v *= p; } const int N = 10000000 + 5; int MAXX = -1; bool flagsum; int ptot = 0; int num[N]; int father[N]; int prime[N]; bool check[N]; int fanwei[N]; int leftprime[N]; int lans[N], rans[N]; void Euler() {ll now;for (int i = 2; i <= MAXX; i ++){if (!check[i]){prime[ptot ++] = i;}for (int j = 0; j < ptot; j ++){now = 1LL * prime[j] * i;if (now > MAXX){break;}check[now] = 1;leftprime[now] = prime[j];if (i % prime[j] == 0){break;}}} } bool get_ans(int fa, int l, int r) {int flag = 0;if (l > r){return true;}int aim;int len = (r - l - 1) / 2 + ((r - l - 1) & 1);for (int i = 0; i <= len; i++){aim = l + i;if (lans[aim] < l && rans[aim] > r){//cout << fa << " " << l << " " << r << " " << i << endl;//cout << lans[i] << " " << rans[i] << endl;flag = 1;flag = flag && get_ans(aim, l, aim - 1) && get_ans(aim, aim + 1, r);if (flag){father[aim] = fa;return true;}else{return false;}}aim = r - i;if (lans[aim] < l && rans[aim] > r){//cout << fa << " " << l << " " << r << " " << i << endl;//cout << lans[i] << " " << rans[i] << endl;flag = 1;flag = flag && get_ans(aim, l, aim - 1) && get_ans(aim, aim + 1, r);if (flag){father[aim] = fa;return true;}else{return false;}}}return false; } int main() {ios_base::sync_with_stdio(0);cin.tie(0);int n;int cnt;read(n);for (int i = 1; i <= n; i++){read(num[i]);MAXX = max(MAXX, num[i]);}Euler();// for (int i = 1; i <= 20; i++)// {// cout << i << " " << leftprime[i] << endl;// }for (int i = 1; i <= n; i++){rans[i] = n + 1;}for (int i = 1; i <= n; i++){cnt = num[i];if (cnt == 1){continue;}//cout<<i<<" ";if (check[cnt] == 0){//cout << "l "<<cnt << endl;lans[i] = max(fanwei[cnt], lans[i]);fanwei[cnt] = i;continue;}while (check[cnt]){//cout << "l " << cnt << endl;int primenow = leftprime[cnt];lans[i] = max(fanwei[primenow], lans[i]);fanwei[primenow] = i;while (cnt % primenow == 0){cnt /= primenow;}}if (cnt == 1){continue;}else{//cout << "l " << cnt << endl;lans[i] = max(fanwei[cnt], lans[i]);fanwei[cnt] = i;}}for (int i = 1; i <= N; i++){fanwei[i] = n + 1;}for (int i = n; i >= 1; i--){cnt = num[i];if (cnt == 1){continue;}//cout<<i<<" ";if (check[cnt] == 0){//cout << "r "<<cnt << endl;rans[i] = min(fanwei[cnt], rans[i]);fanwei[cnt] = i;continue;}while (check[cnt]){//cout << "r "<<cnt << endl;int primenow = leftprime[cnt];rans[i] = min(fanwei[primenow], rans[i]);fanwei[primenow] = i;while (cnt % primenow == 0){cnt /= primenow;}}if (cnt == 1){continue;}else{// cout << "r "<<cnt << endl;// cout << cnt << endl;rans[i] = min(fanwei[cnt], rans[i]);fanwei[cnt] = i;}}// for(int i=1;i<=n;i++)// {// cout<<i<<" "<<lans[i]<<" "<<rans[i]<<endl;// }flagsum = get_ans(0, 1, n);if (!flagsum){cout << "impossible" << endl;}else{for (int i = 1; i <= n; i++){cout << father[i];if (i != n){cout << " ";}}cout << endl;}return 0; }
G
几何题
H
小的直接暴力 大的加给大的
I
背包DP 记录路径还需要一个二维数组
/*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef pair<int, int> PINT; typedef long long ll; typedef unsigned long long ull; const double eps = 1e-8; const int dir[8][2] = {{0, 1}, {1, 0}, {0, -1}, { -1, 0}, {1, 1}, {1, -1}, { -1, -1}, { -1, 1}}; const int mod = 1e9 + 7, gakki = 5 + 2 + 1 + 19880611 + 1e9; const int MAXN = 1e6 + 5, MAXM = 1e5 + 5; const int MAXQ = 100010, INF = 1e9; //int to[MAXM << 1], nxt[MAXM << 1], Head[MAXN], tot = 1; /*inline void addedge(int u, int v, ll c) {to[++tot] = v;nxt[tot] = Head[u];cost[tot] = c;Head[u] = tot; }*/ inline void read(int &v) {v = 0;char c = 0;int p = 1;while (c < '0' || c > '9'){if (c == '-'){p = -1;}c = getchar();}while (c >= '0' && c <= '9'){v = (v << 3) + (v << 1) + c - '0';c = getchar();}v *= p; } struct node {int first, second, index; } bag[505]; bool cmp(node a, node b) {return (a.first - a.second) > (b.first - b.second); } int dp[505][10005]; int print[505][10005]; PINT before[505][10005]; stack<int> anser; int main() {ios_base::sync_with_stdio(0);cin.tie(0);int n, c;scanf("%d %d", &n, &c);for (int i = 1; i <= n; i++){scanf("%d %d", &bag[i].first, &bag[i].second);bag[i].index = i;}sort(bag + 1, bag + 1 + n, cmp);int ans = 0;for (int i = 1; i <= n; i++)for (int j = 0; j <= c; j++){dp[i][j] = -INF;}dp[0][0] = 0;PINT ed = make_pair(0, 0);for (int i = 1; i <= n; i++){for (int j = 0; j <= c; j++){if (dp[i - 1][j] > dp[i][j]){dp[i][j] = dp[i - 1][j];before[i][j] = make_pair(i - 1, j);print[i][j] = print[i - 1][j];}}for (int j = 1; j <= c; j++){if (j >= bag[i].second && j + bag[i].first - bag[i].second <= c){if (dp[i - 1][j - bag[i].second] != -INF){if (dp[i][j] < dp[i - 1][j - bag[i].second] + 1){dp[i][j] = dp[i - 1][j - bag[i].second] + 1;print[i][j] = bag[i].index;before[i][j] = make_pair(i - 1, j - bag[i].second);if (dp[i][j] > ans){ans = dp[i][j];ed = make_pair(i, j);}}}}}}int printnow;cout << ans << endl;for (; ed.first; ed = before[ed.first][ed.second]){if (printnow != print[ed.first][ed.second] && print[ed.first][ed.second] != 0){anser.push(print[ed.first][ed.second]);}printnow = print[ed.first][ed.second];}while (!anser.empty()){cout << anser.top() << " ";anser.pop();}return 0; }
J
找规律题
我们可以通过打暴力程序对比发现每个2一轮一轮地模拟和一个一个地模拟得到的结果是一样的
但是直接把一个一个滚的模拟交上去会T7 需要再简化一下
每当遇到一个二 找到它左边最近的0和右边最近的0位置分别为L与R
则这一段数列除了L+R-i这个位置变成0 其他位置都会变成1
K
概率题