文章目录

  • 比赛过程
  • 题解
    • B
      • 题意
      • 解法
      • 代码
    • D
      • 题意
      • 解法
      • 代码
    • F
      • 题意
      • 解法:
      • 代码:
    • I
      • 题意
      • 解法
      • 代码
    • J
      • 题意:
      • 思路:
      • 代码:

比赛过程

韬:
  比赛中过了D和I,先看的D,看了好一会儿没啥想法于是去做I,I题不难但还是卡了很久,还是题目做的少了,I过了后又回头看D,D大概猜到了套路但是没敢写,写了交了几发都wa了,就开始怀疑思路是不是不对,手动模拟了几次觉得思路没啥问题,最后发现问题出在一个小细节上,还是太粗了,目前做这种稍难一点的题,还是只能去猜他的套路,严密证明这一块实力不足,导致有时候怀疑自己不敢写

Cncn:
  犯了低级错误,开局直接奔A,以为A题干短而且这种数组问题有些似曾相识,花了1个半小时尝试了很多想法结果连样例都过不了,期间也想到过线段树,但是无果,只得放弃。(赛后看到4页的官方题解我人都傻了)
  这时候队友已经把I过了,之后帮助队友想了想D的一种特殊情况,感觉没帮上啥大忙0.0。然后看到有人写B就看了一眼,发现很显然是个背包DP,借助了DP专题A题blank的经验。
  最后开F,想得简单了,交了3发没过。

坤坤:
  今天比赛自己十分混乱,开场和队友商量看C,遇上小学期第一天下午老师讲课,边听课边思考,一度裂开。后面想到了方法但是还是wa了(枯了)。

题解

B

题意

​ 一个人想要升两级,需要的经验分别为 s1,s2s1,s2s1,s2 。有 nnn 个任务,做每个任务需要一定的时间从而获得一些经验,对于同一个任务,不同等级做花费的时间和获得的经验都不一样,第一次升级时如果经验溢出了可以累加到第二阶段,注意只能升完一级才能生第二级。

解法

​   熟悉的采药的气息,妥妥的背包已经不能再明显了。

分析:

  因为升级有两个阶段,所以 $ dp $ 数组肯定比01背包的多一维,所以用 dpi,j,kdp_i,_j,_kdpi​,j​,k​ 表示:选到第 iii 个任务时,第一阶段经验为 jjj ,第二阶段经验为 kkk 时用的最小的时间,注意当 j≠s1,k>0j\neq s1,k>0j​=s1,k>0 时 dpi,j,kdp _i,_j,_kdpi​,j​,k​ 不能实现没有意义,只是作为中间的递推介质。

首先:

  稍微改A一下01背包的模板:

for(int i=1;i<=n;++i)//枚举n个任务for(int j=0;j<=s1;++j)//第一阶段剩余经验for(int k=0;k<=s2;++k)//第二阶段剩余经验work();//状态转移

状态转移:

​     状态转移方程也很好想,就是任务的做与不做,主要是分类讨论麻烦:

​ (A)(A)(A) j<s1:j<s1:j<s1:

​       j+task[i].exp<s1:dp[i+1][j+task[i].exp][k]⇒j+task[i].exp<s1:dp[i+1][j+task[i].exp][k] \Rightarrowj+task[i].exp<s1:dp[i+1][j+task[i].exp][k]⇒

                        max(dp[i+1][j+task[i].exp][k],dp[i][j][k]+task[i].time)max(dp[i+1][j+task[i].exp][k],dp[i][j][k]+task[i].time)max(dp[i+1][j+task[i].exp][k],dp[i][j][k]+task[i].time)

​       j+task[i].exp≥s1:dp[i+1][s1][k+(j+task[i].exp−s1)]⇒j+task[i].exp \ge s1:dp[i+1][s1][k+(j+task[i].exp-s1)]\Rightarrowj+task[i].exp≥s1:dp[i+1][s1][k+(j+task[i].exp−s1)]⇒

                     max(dp[i+1][s1][k+(j+task[i].exp−s1)],dp[i][j][k]+task[i].time)max(dp[i+1][s1][k+(j+task[i].exp-s1)],dp[i][j][k]+task[i].time)max(dp[i+1][s1][k+(j+task[i].exp−s1)],dp[i][j][k]+task[i].time)

​ (B)(B)(B) k<s2:k<s2:k<s2:

​       dp[i+1][s1][min(k+task[i].exp,s2)]⇒dp[i+1][s1][min(k+task[i].exp,s2)] \Rightarrowdp[i+1][s1][min(k+task[i].exp,s2)]⇒

​                      max(dp[i+1][s1][min(k+task[i].exp,s2)],dp[i][s1][k]+task.time)max(dp[i+1][s1][min(k+task[i].exp,s2)],dp[i][s1][k]+task.time)max(dp[i+1][s1][min(k+task[i].exp,s2)],dp[i][s1][k]+task.time)

​   值得注意的是当 j<s1j<s1j<s1 时也要运行BBB 式,否则会出现某个任务没有考虑到放在第二阶段完成的情况,比如完成 task[1]task[1]task[1] 不足 以升至第二阶段,所以对于 task[1]task[1]task[1] 来说 dp[i][s1][k]dp[i][s1][k]dp[i][s1][k] 就无法更新,遍历到之后的 tasktasktask 就考虑不到 task[1]task[1]task[1] 的情况。

优化:

  可以发现第一维只有两个状态:iii 和 i+1i+1i+1,所以用滚动数组降阶。

注意:

​   必须事先按第一阶段的经验值从小到大给任务排个序,否则会wa,举个例子,假如s1=100,s2=40s1=100,s2=40s1=100,s2=40,有三个任务,第一阶段 获得的经验值分别为90、40、40,如果按正常顺序来只能溢出30给第二阶段,此时如果剩下任务的第二阶段经验值无法补满就会输出-1,而如果排个序变成40、40、90就会溢出70直接把第二阶段也填满。可以自己试试下面这个样例排序与否的区别:

3 100 40
90 10 1 1
40 10 1 1
40 10 1 1
//正确答案:30

代码

#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<stack>
#include<string>
#include<cstring>
#include<cstdio>
#include<utility>
#define ll long long
#define ull unsigned long long
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
#define pi acos(-1)
#define lowbit(x) ((x)&(-(x)))
#define debug(x) cout<<x<<'\n'
#define FOR(a,b,c) for(int a=b;a<=c;a++)
#define RFOR(a,b,c) for(int a=b;a>=c;a--)
#define debug(x) cout<<x<<'\n'
using namespace std;
typedef pair<int,int> P;
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};
const ll INF=0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
const double eps = 1e-10;
ll gcd(ll a, ll b) {return b==0?a:gcd(b, a%b);}
ll lcm(ll a, ll b) {return a/gcd(a, b)*b;}
ll mul(ll a,ll b){ll ans=0;a%=mod,b%=mod;while(b) { if(b&1) ans = (ans+a)%mod; a = (a*2)%mod; b >>= 1; }return ans;}
ll powmod(ll a,ll b){ ll ans = 1, pow = a; while(b) { if(b&1) ans = (ans*pow)%mod; pow = (pow*pow)%mod; b >>= 1; } return ans;}
//(b/a)%p=b*a^(p-2)%p
int pr(ll num){if(num == 1) return 0;if(num ==2|| num==3 ) return 1 ;if(num %6!= 1&&num %6!= 5) return 0 ;int tmp =sqrt( num);for(int i= 5;i <=tmp; i+=6 )if(num %i== 0||num %(i+ 2)==0 )return 0 ;return 1 ;}
int Day(int y,int m, int d){if(m==1||m==2) { m+=12; y--; }int w=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;return w+1;}
int pri[10005];
void getpri(){memset(pri,true,sizeof(pri));pri[0]=pri[1]=0;for(int i=2;i<=10000000;i++){if(pri[i]){for(int j=2*i;j<=10000000;j+=i) pri[j]=0;}}}
const int maxn=3e5+5;
struct ac{ll x, t, y, r;
} a[501];
bool cmp(ac a,ac b){return a.x < b.x;
}
ll dp[2][501][501];
int main() {IO;ll n, s1, s2, f = 0;cin >> n >> s1 >> s2;FOR(j,0,s1){FOR(k,0,s2){dp[0][j][k] = INF;}}dp[0][0][0] = 0;FOR(i,1,n){cin >> a[i].x >> a[i].t >> a[i].y >> a[i].r;}sort(a + 1, a + 1 + n, cmp);FOR(i,1,n){FOR(j,0,s1){FOR(k,0,s2){dp[f ^ 1][j][k] = dp[f][j][k];}}FOR(j,0,s1){FOR(k,0,s2){if(dp[f][j][k]!=INF){if(j<s1){if(j+a[i].x<s1){dp[f ^ 1][j + a[i].x][k] = min(dp[f ^ 1][j + a[i].x][k], dp[f][j][k] + a[i].t);}else{dp[f ^ 1][s1][min(k + j + a[i].x - s1, s2)] = min(dp[f ^ 1][s1][min(k + j + a[i].x - s1, s2)], dp[f][j][k] + a[i].t);}}if(k<s2){dp[f ^ 1][j][min(k + a[i].y, s2)] = min(dp[f ^ 1][j][min(k + a[i].y, s2)], dp[f][j][k] + a[i].r);}}}}f ^= 1;}if(dp[f][s1][s2]!=INF) cout << dp[f][s1][s2] << endl;else cout << -1 << endl;return 0;
}

D

题意

  给出一个长度为2n的循环字符串,问是否能重新排列使得没有相同的长度为n的子串。

解法

分四种情况:

  1. 只有一种字符,不可能成功;
    有两种字符,其中一种占一半以上,另一半一定<=n.

  2. 少的一种小于3时,不可能成功;

  3. 少的一种至少为3个,成功;

  4. 如果种类多于2种,成功;

代码

vector<char> v;
map<char, ll> mp;
int main() {string s;cin >> s;ll n = (int)s.length() / 2;for (auto it : s) {if (mp[it] == 0)v.push_back(it);mp[it]++;}if (v.size() == 1) {puts("NO");return 0;}int flag = 0;if (v.size() == 2) {if ((mp[v[0]] > n && mp[v[1]] < 3) || (mp[v[1]] > n && mp[v[0]] < 3)) {puts("NO");return 0;}if (mp[v[0]] > n && mp[v[1]] >= 3) {mp[v[1]]--;flag = 1;}else if (mp[v[1]] > n && mp[v[0]] >= 3) {char tem = v[0];v[0] = v[1];v[1] = tem;mp[v[1]]--;flag = 1;}}puts("YES");queue<char> q;char la = '0';for (auto it : v){q.push(it);if (la != '0') q.push(la);if (mp[it] > n) la = it;}while (!q.empty()) {char t = q.front();q.pop();int len = min(mp[t], n);mp[t] -= len;for1(i, len) cout<<t;}if (flag == 1)cout << v[1];puts("");
}

F

题意

  有一棵根为 1 的树,每个节点初始都是白色, Alice 能在这棵树的某个节点放下一个棋子,并使得该节点变为黑色,然后从 Bob 开始,两人能轮流移动这个棋子到当前所在节点的任意一个白色的祖先或者后代节点(不需要相邻的节点),并且将移动到的节点染为黑色。谁先不能移动就输了。

解法:

  做的时候一直以为他的跳转是只能跳转到当前点的相邻结点,但其实这道题可以跳到任意祖先结点或者后代结点,其实不管是上面说的哪种情况都可以同样用判断图是否存在完美匹配解得。

两种情况:

  1. 存在完美匹配:那么不管Alice从哪个点起步,Bob都可以找到该点的匹配点并染色,这样下来最先无法染色的一定是Alice。
  2. 不存在完美匹配:那么Alice可以选择不在最大匹配中的点起步,假设起始点为a1,Bob走的下一步为b1,b1其实必在最大匹配中,因为如果不在,那么(a,b) 又构成一个匹配,与最大匹配矛盾。那么接下来Alice就可以采取第一种情况中Bob的操作,因为Bob接下来是无法到达最大取匹配外的点的(假设b3在最大匹配外,那么匹配集(a1,b1),(a2,b2),(a3,b3)…的匹配数一定大于最大匹配(b1,a2),(b2,a3)…(后边都一样))所以Alice只要走最大匹配外的点,接下来Bob只能走最大匹配内的点,类似于第一种情况只不过Bob先手,所以Alice必赢。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <string>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define ms(a, x) memset(a, x, sizeof(a))
#define fore(i, a, n) for (ll ll i = a; i < n; i++)
#define ford(i, a, n) for (ll ll i = n - 1; i >= a; i--)
#define si(a) scanf("%d", &a)
#define sl(a) scanf("%lld", &a)
#define sii(a, b) scanf("%d%d", &a, &b)
#define siii(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define sll(a, b) scanf("%lld%lld", &a, &b)
#define slll(a, b, c) scanf("%lld%lld%lld", &a, &b, &c)
#define debug(a) cout << a << endl
#define pr(a) printf("%d ", a)
#define endl '\n'
#define pi acos(-1.0)
#define tr t[root]
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define ull unsigned long long
#define py puts("Yes")
#define pn puts("No")
#define pY puts("YES")
#define pN puts("NO")
#define re(i, a, b) for (int i = a; i <= b; ++i)
#define de(i, a, b) for (int i = a; i >= b; --i)
#define all(x) (x).begin(), (x).end()
#define ls(x) x.resize(unique(all(x)) - x.begin())
const double eps = 1e-8;
inline int sgn(const double &x) { return x < -eps ? -1 : x > eps; }
typedef long long ll;
const ll inf = 0x3f3f3f3f;
const int MAXN = 1e5 + 5;
template <class T>
inline void cmin(T &a, T b) { ((a > b) && (a = b)); }
template <class T>
inline void cmax(T &a, T b) { ((a < b) && (a = b)); }
const ll mode = 20090126;
//上边只是头int f[MAXN];
vector<int> edge[MAXN];void dfs(int x, int fa)
{for (auto to : edge[x]){if (to == fa)continue;dfs(to, x);f[x] += f[to];}if (f[x])f[x]--;elsef[x] = 1;
}int main()
{int n;si(n);for (int i = 1; i < n; i++){int u, v;sii(u, v);edge[u].push_back(v);edge[v].push_back(u);}dfs(1, 0);if (!f[1])printf("Bob\n");elseprintf("Alice\n");
}

  代码中的dfs过程是因为这道题不要求跳转的点一定是相邻的,和真实情况的图的匹配不太一样,只要两个点互为祖先和后代结点,这里就视为可以匹配。

  实际上判断图是否存在完美匹配可以参考:https://blog.csdn.net/lycheng1215/article/details/78368002

I

题意

  两个人A和B分别持有两个数组,每一轮都要扔出去一个数,直到最后都只剩下最后一个数字。A想要使得两个数的差最多,B则相反。现在给你数组,要你求出两人的最佳决策后最后的答案。

解法

  不管A剩下哪一个数字,B都有办法剩下那个与之相差最小的数。那么答案就是A的所有数与B的所有数字中最小差里面最大的。

代码

int n, a[N], b[N];int main() {scanf("%d", &n);for1(i, n) scanf("%d", a+i);for1(i, n) scanf("%d", b+i);int ans = 0, minn;for1(i, n) {minn = INF;for1(j, n) {minn = min(minn, abs(a[i] - b[j]));}ans = max(ans, minn);}cout<<ans<<endl;
}

J

题意:

  给出一个有n(n为奇数)个点的无向完全图,可以从这张图中分割出任意个圈,任意两个分割出来的圈没有重叠的边,而且图中的每一条边必定属于其中一个圈。圈分割出来后,对于其中的每个顶点的两条边取最大值然后相加作为该圈的重量,问如何分割这张图能使所有圈的重量和最小。

思路:

  点数为奇数,意味着每个点的度数为偶数,那么不难看出价值最小的情况就是对一个点的所有边从小到大排序后,两两为一对作为圈的组成部分。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <string>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <map>
using namespace std;
#define ms(a, x) memset(a, x, sizeof(a))
#define fore(i, a, n) for (ll ll i = a; i < n; i++)
#define ford(i, a, n) for (ll ll i = n - 1; i >= a; i--)
#define si(a) scanf("%d", &a)
#define sl(a) scanf("%lld", &a)
#define sii(a, b) scanf("%d%d", &a, &b)
#define siii(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define sll(a, b) scanf("%lld%lld", &a, &b)
#define slll(a, b, c) scanf("%lld%lld%lld", &a, &b, &c)
#define debug(a) cout << a << endl
#define pr(a) printf("%d ", a)
#define endl '\n'
#define pi acos(-1.0)
#define tr t[root]
#define IO ios::sync_with_stdio(false), cin.tie(0)
#define ull unsigned long long
#define py puts("Yes")
#define pn puts("No")
#define pY puts("YES")
#define pN puts("NO")
#define re(i, a, b) for (int i = a; i <= b; ++i)
#define de(i, a, b) for (int i = a; i >= b; --i)
#define all(x) (x).begin(), (x).end()
#define ls(x) x.resize(unique(all(x)) - x.begin())
const double eps = 1e-8;
inline int sgn(const double &x) { return x < -eps ? -1 : x > eps; }
typedef long long ll;
const ll inf = 0x3f3f3f3f;
const int MAXN = 1e5 + 5;
template <class T>
inline void cmin(T &a, T b) { ((a > b) && (a = b)); }
template <class T>
inline void cmax(T &a, T b) { ((a < b) && (a = b)); }
const ll mode = 20090126;
//上边只是头vector<vector<pair<ll, ll>>> G;int main()
{int n;si(n);G.resize(n + 1);re(i, 1, n * (n - 1) / 2){ll u, v, w;slll(u, v, w);G[u].push_back(make_pair(w, v));G[v].push_back(make_pair(w, u));}re(i, 1, n) sort(all(G[i]));ll ans = 0;for (int i = 1; i <= n; i++)for (int j = 0; j < (n - 1) / 2; j++){ll w1 = G[i][2 * j].first;ll w2 = G[i][2 * j + 1].first;ans += max(w1, w2);}cout << ans << endl;
}

7.10 18级多校适应训练1题解相关推荐

  1. 2017 多校联合训练 3 题解

    Problem 1003 维护一个链表 链表中记录大于等于x的数 一开始链表中插入所有的数 从小到大枚举x 用双指针从左到右跳k次 做完一个x删除这个节点 1 #include<iostream ...

  2. 训练日志 2018.10.18

    花了一周时间把之前学过的算法和题重新看了一下,重新架构了一下知识体系,对 DP 和搜索有了更深刻的认识,这周正式开始图论内容,抽空再将搜索的优化和 A* 算法学习一下 2018.10.18

  3. 跨专业考清华大学的计算机,18级学长跨考清华大学计算机考研经验分享

    18级学长跨考清华大学计算机考研经验分享本站小编 Free考研网/2019-05-28 考清华计算机也考了两年,在这里得到了很多帮助,所以也是时候贡献一下了.先说下我的基本情况吧.我本科是天津大学精仪 ...

  4. 第18届浙江大学校赛 Mergeable Stack

    The 18th Zhejiang University Programming Contest Sponsored by TuSimple 第18届浙江大学校赛的c题 解析:起先是用stack写的模 ...

  5. 10亿级!淘宝大规模图像检索引擎算法设计概览

    进入21世纪以来,伴随着互联网的高速发展,通过图像和视频来进行需求表达越来越成为大家的习惯. 图像搜索与识别算法使得图像视频内容得以结构化和数字化,以便可以在各种检索和分析引擎中被最大限度地挖掘和利用 ...

  6. Staking来袭,10亿级市场打开! | 火星总编时刻NO.31

    Staking将为PoS带来下游金融的机会. 本文旨在传递更多市场信息,不构成任何投资建议. 文 | 林中路 出品 | 火星财经APP(ID:hxcj24h) 火星财经APP(ID:hxcj24h)一 ...

  7. 计算机学院班群头像,【北工大表白墙】计算机类18级3班孙宇辰同学,你是广袤沙漠里的盐。...

    原标题:[北工大表白墙]计算机类18级3班孙宇辰同学,你是广袤沙漠里的盐. ----------------------------------- ❤表白1:孙宇辰同学,现在我在四十多公里外昌平,刚刚 ...

  8. 复旦大学2018--2019学年第一学期(18级)高等代数I期末考试第七大题解答

    七.(本题10分)  设 $V$ 为 $n$ 维线性空间, $\varphi,\psi$ 是 $V$ 上的线性变换, 满足 $\varphi\psi=\varphi$. 证明: $\mathrm{Ke ...

  9. CUGBACM22级暑假小学期训练-贪心

    CUGBACM22级暑假小学期训练-贪心 A - 种树 题意:给一个环,取m个节点,不能取相邻节点,令所取节点的权值之和最大化 思路:dp,用到了最大流中建立反向边的思想使得这个贪心能够"反 ...

  10. CUGBACM22级暑假小学期训练-简单构造

    CUGBACM22级暑假小学期训练-简单构造 这Typora打到9000多字就开始卡了,难绷 A - Gardener and the Capybaras (hard version) 题意:给一个字 ...

最新文章

  1. 沉浸式小说App获得200万美元投资
  2. winrar目录穿越漏洞(更新经验)
  3. Java多线程闲聊(六):synchronized关键字
  4. BOOST_TEST_FOREACH宏相关的测试程序
  5. Android 系统(145)---ODM 开发用户常见需求文档(七)
  6. 给广告打“保”字标、弄风险提示 百度搜索为用户旅游操碎了心
  7. 微软开始测试自己的Google Base
  8. linux内核killler,Linux 的 OOM Killer 机制分析
  9. livevent的几个问题
  10. Android-JNI开发系列《四》Native-Crash定位
  11. Servlet doGet doPost 中获取参数 中文乱码
  12. Codeforces 631E 斜率优化
  13. m6000查看端口状态_中兴ZXR10 M6000维护最常用命令精要
  14. VS2010 无法打开包括文件:“cv.h”
  15. 电力电子技术(12)——整流电路的谐波和功率因数
  16. java.lang.UnsupportedOperationException: Required method instantiateItem was not overridden
  17. Docker容器镜像加速器
  18. 认识并行、并发、多线程
  19. 全基因组关联分析学习资料(GWAS tutorial)20210313更新版
  20. 超市销售数据分析python_python实战案例:超市营业额数据分析

热门文章

  1. JavaScript运算符运算优先级
  2. 知了课堂Day3——微信小程序基础03——组件的一些笔记
  3. graphpad折线图教程_Graphpad Prism5作图教程
  4. 计算机模拟的实例,计算机模拟实例模拟的概念-read.ppt
  5. 计算机专业职业生涯规划书结束语,职业生涯规划书结束语
  6. 让你的FireFox支持迅雷精简版
  7. 【MFC】测边网平差计算
  8. 张孝祥javascript视频教程
  9. vac虚拟声卡我linux,虚拟声卡驱动应用及其原理简要说明
  10. matlab深度DoF图像修复,windows10系统运行dnf提示client.exe损坏的图像解决方法