写在前面:刚来到csdn,写写第一篇题解,菜菜勿骂
本场感受:没怎么学图论直接红温,看完题解发现有个体是板子换根,更红温了
A-序列中的排列
思路
map储存一下,遍历1-k看看有没有都出现即可
代码
void solve() {
ll n;
cin >> n;
map<ll, ll>arr;
ll k;
cin >> k;
for (int i = 1; i <= n; i++) {
ll a;
cin >> a;
arr[a]++;
}
for (int i = 1; i <= k; i++) {
if (arr[i] == 0) {
cout << "NO";
return;
}
}
cout << "YES";
}
B-连分数
思路
只能说不愧是牛客的傻嘚题,直接递推求极限就可以了
代码
void solve() {
cin >> a;
double ans =(a+sqrtl(a*a+4))/2;
cout<<fixed<<setprecision(12)<<ans;
}
C-sum
思路
很明显就能够发现,我们对于每个数如果当前的数组的sum的和大于要等于的sum0,那么就需要重大的开始,将其变为-1e4,否则就从小的开始,变成1e4,顺序遍历加分类讨论即可
代码
ll cmp1(ll a, ll b) {
return a < b;
}
ll cmp2(ll a, ll b) {
return a > b;
}
ll arr[200030];
void solve() {
ll n;
cin >> n;
ll sum;
cin >> sum;
ll sum0 = 0;
for (int i = 1; i <= n; i++) {
cin >> arr[i];
sum0 = sum0 + arr[i];
}
sort(arr + 1, arr + 1 + n, cmp1);
if (sum0 == sum) {
cout << "0";
return;
}
if (sum > sum0) {
for (int i = 1; i <= n; i++) {
sum0 = sum0 - arr[i] + (1e4);
if (sum <= sum0) {
cout << i;
return;
}
}
}
else {
sort(arr + 1, arr + 1 + n, cmp2);
for (int i = 1; i <= n; i++) {
sum0 = sum0 - arr[i] - 1e4;
if (sum >= sum0) {
cout << i;
return;
}
}
}
}
D-最短?路径
思路
一眼的图上dp,但是没学最短路直接寄,赛后学了一下最短路,我们根据迪杰斯特拉做法,知道对于无向图而言,没有负的权值的时候就去贪心最短的到达原点的点就可以了,然后运用到该题上面,实际上对于每个点我们贪心到达该点的隔了j个点没有休息的最小值,其他的点赋值为最大值,跑一遍迪杰斯特拉算法即可
代码
int dist[N + 1][11];
int st[N + 1][11];
void solve() {
int n, m, k;
cin >> n >> m >> k;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)cin >> a[i];
vector<vector<int>> g(n + 1);
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= k; j++) {
dist[i][j] = 1e18;
st[i][j] = 0;
}
}
priority_queue<array<int, 3>, vector<array<int, 3>>, greater<>> q;
if (k != 0) {
dist[1][1] = 1;
q.push({ 1, 1, 1 });
}
dist[1][0] = a[1];
q.push({ a[1], 1, 0 });
while (q.size()) {
auto [w, i, j] = q.top();
q.pop();
if (st[i][j])continue;
st[i][j] = 1;
for (auto ne : g[i]) {
//休息
if (dist[ne][0] > a[ne] + w) {
dist[ne][0] = a[ne] + w;
q.push({ dist[ne][0], ne, 0 });
}
//不休息
if (j + 1 <= k && dist[ne][j + 1] > w + 1) {
dist[ne][j + 1] = w + 1;
q.push({ dist[ne][j + 1], ne, j + 1 });
}
}
}
int ans = 1e18;
for (int i = 0; i <= k; i++)ans = min(ans, dist[n][i]);
cout << ans ;
}
E-k-路径
思路
赛时没有看出来,觉得人少没有尝试,但赛后补题时发现是一个很板子的题,我们对于每个点而言,都去跑一边最大路径,也就是经过该点的最长路,利用换根dp来优化一下时间为o(n),其次,我们定义两个数组维护到达该点的最大值和次大值,然后,我们利用第三个数组维护从树的根部到该点的最长路,最后将每个点的c值顺序遍历一遍即可
代码
vector<ll>arr[N];
vector<ll>dp1(N);
vector<ll>dp2(N);
vector<ll>dp3(N);//代表父亲节点上面的最大值
vector<ll>c(N);
vector<ll>w(N);
vector<ll>ans(N);
void maxx(ll& a, ll& b, ll c) {
if (c > a) {
b = a;
a = c;
}
else if (c > b) {
b = c;
}
}
void dfs(ll u, ll v) {
for (auto now : arr[u]) {
if (now != v) {
dfs(now, u);
maxx(dp1[u], dp2[u], dp1[now] + w[now]);
}
}
}
void dfs2(ll u, ll v) {
if (u != 1) {
maxx(dp1[u], dp2[u], dp3[u]);
}
for (auto now : arr[u]) {
if (now != v) {
if (dp1[u] != dp2[u] && dp1[u] == dp1[now] + w[now]) {
dp3[now] = dp2[u] + w[u];
}
else {
dp3[now] = dp1[u] + w[u];
}
dfs2(now, u);
}
}
}
void solve() {
ll n;
cin >> n;
for (int i = 1; i <= n; i++) {
arr[i].clear();
}
for (int i = 1; i <= n; i++) {
cin >> c[i];
}
for (int i = 1; i <= n; i++) {
cin >> w[i];
dp1[i] = 0;
dp2[i] = 0;
ans[i] = -1e18;//记录每个点的最小值
}
for (int i = 1; i < n; i++) {
ll a, b;
cin >> a >> b;
arr[a].push_back(b);
arr[b].push_back(a);
}
dfs(1, 0);
dfs2(1, 0);
for (int i = 1; i <= n; i++) {
ans[c[i]] = max(ans[c[i]], w[i] + dp1[i] + dp2[i]);
}
for (int i = 1; i <= n; i++) {
if (ans[i] != -1e18) {
cout << ans[i] << ' ';
}
else {
cout << -1 << ' ';
}
}
}
其他的就不会喽