A.Direction Change

  • 讨论一下每种移动的情况即可。先交替,然后再走多的。
  • 走多的过程需要交替在其他方向移动。
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;int main()
{int t;cin >> t;for(int i = 0;i<t;i++){int n,m;cin >> n >> m;int r = m - 1; //向右移动int d = n - 1; //向下移动if(abs(d-r) <=1) cout << r + d << endl;else{if(r == 0 || d == 0) cout << -1 << endl;else{int a = 0;a += min(r,d)*2;a+=2*(max(r,d) - min(r,d));if((max(r,d) - min(r,d)) % 2 == 1) a--;cout << a << endl;}   }}system("pause");return 0;
}

B.Social Distance

  • 从需要最多椅子的人开始,递减安排
  • 每多来一个人,前一个安排的人需要用到额外的与其数量对应的空椅子。
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;int main()
{int t;cin >> t;for(int i = 0;i<t;i++){int n,m;cin >> n >> m;   //人的数量 椅子的数量int a[n];for(int k = 0;k<n;k++) cin >> a[k];sort(a,a+n);m--;m-=a[n-1];  //空椅子的数量n--;if(m<0) cout<<"NO"<<endl;else{bool flag = true;while(n>=1)  //还有人未被安排{m-=a[n];m--;if(m<0) {flag = false;break;}n--;}if(flag) cout << "YES" << endl;else cout << "NO" << endl;}}system("pause");return 0;
}

C.Make it Increasing

  • 考察最优解的性质:最优解中一定包含一个0
  • 0右侧仅包含加,0左侧仅包含减
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;int main()
{ll n;cin >> n;ll a[n];for(int i = 0;i<n;i++) cin >> a[i];ll ans = LONG_LONG_MAX;for(int i = 0 ;i < n;i++)   //枚举每一位为0的位子{ll pre1 = 0;ll temp = 0;for(int j = i - 1;j>=0;j--){ll m = (ll)ceil((double)abs((double)pre1 - 1) / a[j]);temp += m;pre1 = -m * a[j];}ll pre2 = 0;for(int j = i + 1;j<n;j++){ll m = (ll)ceil(double(pre2 + 1) / a[j]);temp += m;pre2 = m * a[j];}ans = min(ans,temp);}cout << ans << endl;system("pause");return 0;
}

D.Optimal Partition(DP优化)

思路(线段树)

  • 容易列出dp方程:dp[j],以j号下标结尾的最大和
    a=maxpre[j]−pre[i]>0{dp[i]+j−i}b=maxpre[j]−pre[i]<0{dp[i]+i−j}c=maxpre[j]=pre[i]{dp[i]}dp[j]=max{a,b,c}a = max_{pre[j] - pre[i] > 0}\{dp[i] + j - i\} \\ b = max_{pre[j] - pre[i] < 0}\{dp[i] + i - j\} \\ c = max_{pre[j] = pre[i]}\{dp[i]\} \\ dp[j] = max\{a,b,c\} a=maxpre[j]−pre[i]>0​{dp[i]+j−i}b=maxpre[j]−pre[i]<0​{dp[i]+i−j}c=maxpre[j]=pre[i]​{dp[i]}dp[j]=max{a,b,c}
  • 对于每个j需要找到与pre[j]满足一定条件的所有pre[i],并求其对应的最大值。
  • 维护某个大小前缀和的dp[i]-i或dp+i或dp[i]的最大值。每次查询小于,大于,等于某个前缀和所有前缀和对应的上述a,b,c的最大值。
  • 前缀和取值有限,将前缀和离散化。方法是将其排序。
  • 可以使用线段树维护。每次查询或更新某个区间的最值。

线段树

  • 复杂度O(logn)O(logn)O(logn)-区间的连续性

代码

#include<iostream>
#include<algorithm>
#include<map>
#include<stdio.h>
#include<string.h>
#include<unordered_map>
#include<vector>
#include<queue>
#include<set>
#include<math.h>
typedef long long ll;
using namespace std;ll d1[9500001];
ll d2[9500001];
ll d3[9500001];
ll a[500001];
ll f[500001];
ll pr[500001];
void build(int s, int t, int p,ll d[]) {// 对 [s,t] 区间建立线段树,当前根的编号为 pif (s == t) {d[p] = -1e18;return;}int m = s + ((t - s) >> 1);// 移位运算符的优先级小于加减法,所以加上括号// 如果写成 (s + t) >> 1 可能会超出 int 范围build(s, m, p * 2,d), build(m + 1, t, p * 2 + 1,d);// 递归对左右区间建树d[p] = -1e18;
}ll query(int l, int r, int s, int t, int p,ll d[]) {// [l, r] 为查询区间, [s, t] 为当前节点包含的区间, p 为当前节点的编号// if(r < l) return LONG_LONG_MIN + 1e18;if (l <= s && t <= r)return d[p];  // 当前区间为询问区间的子集时直接返回当前区间的和int m = s + ((t - s) >> 1);ll ans = LONG_LONG_MIN;if (l <= m) ans = max(ans,query(l, r, s, m, p * 2,d));// 如果左儿子代表的区间 [l, m] 与询问区间有交集, 则递归查询左儿子if (r > m) ans = max(ans,query(l, r, m + 1, t, p * 2 + 1,d));// 如果右儿子代表的区间 [m + 1, r] 与询问区间有交集, 则递归查询右儿子return ans;
}// C++ Version
void update(int index,ll c, int s, int t, int p, ll d[]) {if (s == t && s== index) {d[p] = max(d[p],(ll)c);return;} int m = s + ((t - s) >> 1);if(index <= m) update(index,c,s,m,2*p,d);else update(index,c,m+1,t,2*p+1,d);d[p] = max(d[p*2],d[p*2+1]);
}int main()
{int t;cin >> t;for(int i = 0;i<t;i++){int n;cin >> n;memset(pr,0,n*sizeof(ll));memset(f,0,n*sizeof(ll));vector<ll> pre;for(int k = 0;k<n;k++){cin >> a[k];ll pre1; if(k == 0) pre1=  0 ; else pre1 = pre[k-1];pre.push_back(pre1 + a[k]);pr[k] = pre1 + a[k];}//cout << pre[n-1] << endl;sort(pre.begin(),pre.end());pre.erase(unique(pre.begin(),pre.end()),pre.end());int n1 = pre.size();build(1,n1,1,d1);build(1,n1,1,d2); build(1,n1,1,d3);int w = lower_bound(pre.begin(),pre.end(),pr[0]) - pre.begin() + 1;if(a[0] < 0) f[0]=-1; else if(a[0] > 0) f[0] = 1;  else f[0]=0;update(w,f[0],1,n1,1,d1);update(w,f[0],1,n1,1,d2); update(w,f[0],1,n1,1,d3);for(int k = 1;k<n;k++){w = lower_bound(pre.begin(),pre.end(),pr[k]) - pre.begin() + 1;f[k]=-1e10;//cout << query(1,w-1,1,n1,1,d1) << endl;if(w-1>=1) f[k]=query(1,w-1,1,n1,1,d1) + k;ll a;if(pr[k]<0) a=-k-1;else if(pr[k]>0) a=k+1; else a=0;if(w+1<=n1) f[k] = max(query(w+1,n1,1,n1,1,d2)- k,f[k]) ;f[k] = max(query(w,w,1,n1,1,d3),f[k]);f[k] = max(a,f[k]);update(w,f[k]-k,1,n1,1,d1);update(w,f[k]+k,1,n1,1,d2);update(w,f[k],1,n1,1,d3);}cout << f[n-1] << endl;}system("pause");
}

E. Half Queen Cover(GOOD)

思路(找必要条件 然后构造)

  • 假定kkk个皇后满足题意,这kkk个皇后至多占据k行,至多占据k列。因此至少n−kn-kn−k行没有皇后占据,至少n−kn-kn−k列没有皇后占据。因此至少有(n−k)×(n−k)(n - k) \times (n-k)(n−k)×(n−k)格点未被占据。

  • 必须要使这k个半皇后覆盖至少这(n−k)×(n−k)(n - k) \times (n - k)(n−k)×(n−k)个格点。考察这些格点的第一行,第一列所有格点。每一个只能由一个不同的半皇后得到。因此必须要有
    k≥(n−k−1)+(n−k−1)+1k \geq (n - k - 1) + (n - k - 1) + 1 k≥(n−k−1)+(n−k−1)+1
    即k≥⌈2n−13⌉k \geq \lceil \frac{2n - 1}{3} \rceilk≥⌈32n−1​⌉
    目标转换为构造k=(n−k−1)+(n−k−1)+1k =(n - k - 1) + (n - k - 1) + 1 k=(n−k−1)+(n−k−1)+1的方案。

构造思路1(官方)

  • 分n的不同情况讨论。

  • 当n=3x+2n = 3x+2n=3x+2,则k=2x+1k = 2x+1k=2x+1。放置策略如图所示:

  • 当n=3xn = 3xn=3x,则k=2xk = 2xk=2x.先在右下角放置1个,转换为n=3(x−1)+2n = 3(x-1)+2n=3(x−1)+2,k=2(x−1)+1k = 2(x-1) + 1k=2(x−1)+1的上述问题。

  • 当n=3x+1n = 3x+1n=3x+1,则k=2x+1k = 2x+1k=2x+1。现在右下角放置2个。转换为n=3(x−1)+2n = 3(x-1)+2n=3(x−1)+2,k=2(x−1)+1k = 2(x-1) + 1k=2(x−1)+1的上述问题。

#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;int main()
{int n;cin >> n;int count = 0;int n1 = n;if(n == 1) {cout <<1 << endl;cout << 1 << " " << 1 << endl;return 0;}while(n%3 !=2){n--;    count ++;}int x = (n - 2) / 3;count += (2*x+1);cout << count << "\n";for(int i = n+1;i<=n1;i++){cout << i << " " << i << "\n";}//开始的x+1个放在左上角for(int i = 1;i<=x+1;i++) cout << i << " " << x+2-i<<"\n";//剩下的x个放在右下角for(int i = n-x+1;i<=n;i++) cout<<i<<" "<<2*n-x+1 - i << "\n";//system("pause");return 0;
}

构造思路2

  • 如果能使得(n−k)∗(n−k)(n-k)*(n-k)(n−k)∗(n−k)的方格点紧靠一起,形成方阵,最有可能使用为了将该方阵第一行,第一列的格点填满而必须添加的皇后将该方阵填满的目的。
  • 可以让未摆放皇后的行集中在下侧,未摆放皇后的列集中在右侧。从而形成(n−k)∗(n−k)(n-k)*(n-k)(n−k)∗(n−k)的方阵。在左上角的k×kk \times kk×k方阵中,每条蓝线和绿线上都应摆放一个半皇后,如图所示,显然存在将这些皇后放在不同行,不同列上的摆法(打勾位子)。
  • 当k=(n−k−1)+(n−k−1)+1k =(n - k - 1) + (n - k - 1) + 1k=(n−k−1)+(n−k−1)+1不存在整数解时,参照官方解答在右下角摆放后再转换为上述问题。
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;int main()
{int n;cin >> n;int count = (int)ceil((double)(2*n - 1) /3);cout << count << endl;if(n==1) {cout << 1 << " " << 1 << endl;return 0;}while((2*n - 1) % 3 != 0){cout << n << " " << n << endl;n--;}int k = (2*n-1)/3;int j = 1;for(int i = 1;i<=k;i++){cout << i <<" "<< j << endl;j+=2;if(j>k) j=2;}system("pause");return 0;
}

F-Edge Elimination(VeryGood)(Very \ Good)(Very Good)


思路

本题是一道很好的构造题。

  • 由树形结构的特殊性:将该树进行分层。

  • 必要条件(observation1):考察对于单个结点所涉及的边的删除情况。设该结点为vIv_IvI​

    • 当deg(vi)deg(v_i)deg(vi​)是奇数。与其相连的第一条边的删除需要其所连接的另一个顶点的度为奇数。与其相连的第二条边的删除需要其所连接的另一个顶点的度为偶数。以此类推
    • 当deg(vi)deg(v_i)deg(vi​)是偶数,同理。
  • 必要条件(observation2):对于每条边,在删除时刻与其关联的点的度的奇偶都是确定的。 这可以从叶节点出发自底向上为每条边得出在删除时刻其关联的两个顶点的度是奇数(称这样的边为奇边)还是偶数(称这样的边为偶边)。

    • 由于树形结构的分层特殊性,且每个结点只有一个parent,才可以这样做。
    • 根据当前结点的实际度是奇数还是偶数,observation1,以及当前结点关联的边的奇偶情况。关系如果不能满足observation1的删除条件,则肯定输出NO
  • 考虑自底向上,红色结点关联的边存在一个合适的删除顺序,橙色结点关联的边也有一个合适的删除顺序。但是边1的删除顺序可能依赖于边2是否删除,也依赖于红橙结点共同的父节点的边的删除顺序,因为这样才能保证边1满足其关联的边同奇,同偶(具体哪一种前面已经给出了),从而能够删除边1。

  • 在给定红色结点的任意一个可行删除顺序时,并不会与边2产生任何的拓扑关系。

  • 于是可得出:若将原始图每条边作为一个结点(设为图G),对原始图中每个结点,根据其奇偶度任意安排一种边的删除顺序,并将该顺序体现在G中则G是有向无环图。在G上运行拓扑排序即可。

#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <map>
#include <queue>
#include <chrono>
#include <math.h>
#include <unordered_map>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;int dfs(vector<array<int,2>> adj[],vector<int> adj_edge[],int n,int c,int f)
{vector<int> even;vector<int> odd;int index = -1;for(array<int,2> e:adj[c]){if(e[1]!=f){int v = dfs(adj,adj_edge,n,e[1],c);if(v==-1) return -1;else if(v==1)  odd.push_back(e[0]);              //是奇边else even.push_back(e[0]);   //0,是偶边}else index = e[0];   }//回退至上一个结点int o_size = odd.size(); int e_size = even.size();int ret = -1;if(adj[c].size()%2==0){if(index!=-1&&o_size == e_size+1) {even.push_back(index);ret=0;}   //奇数等于偶数加1,加入奇数边else if(index!=-1&&e_size==o_size+1) {odd.push_back(index);ret=1;} //偶数等于奇数加1,加入奇数边else if(index==-1&&e_size==o_size) {ret=1;}}else{if(index!=-1&&e_size==o_size) {odd.push_back(index);ret=1;}   //偶数等于奇数,加入奇数边else if(index!=-1&&o_size==e_size+2) {even.push_back(index);ret=0;}  //奇数比偶数多2,加入偶数边else if(index ==-1 && o_size == e_size+1) {ret=1;}if(ret!=-1) {if(even.size()>=1)adj_edge[odd[odd.size()-1]].push_back(even[even.size()-1]);odd.pop_back();}}if(ret!=-1){assert(even.size() == odd.size());for(int i = even.size() - 1;i>=0;i--){adj_edge[even[i]].push_back(odd[i]);if(i-1>=0) adj_edge[odd[i]].push_back(even[i-1]);}}return ret;
}int main()
{int t;cin >> t;for(int i =0 ;i<t;i++){int n;cin >> n;vector<array<int,2>> adj[n];vector<int> adj_edge[n-1];vector<array<int,2>> edge;for(int k = 0;k<n-1;k++){int u,v;cin >> u >> v;u--,v--;adj[u].push_back({k,v}); adj[v].push_back({k,u});edge.push_back({u,v});}int v = dfs(adj,adj_edge,n,0,-1);if(v==-1) cout<<"NO"<<endl;else   //run topological sort{cout << "YES" << endl;queue<int> q;//遍历邻接表确定入度int ind[n-1];memset(ind,0,(n-1)*sizeof(int));for(int k = 0;k<n-1;k++)for(int v:adj_edge[k])ind[v]++;for(int k = 0;k<n-1;k++) if(ind[k] == 0) {q.push(k);}while(!q.empty()){int u = q.front();cout << edge[u][0]+1 << " " << edge[u][1]+1 << endl;q.pop();for(int v : adj_edge[u]){ind[v]--;if(ind[v] == 0){q.push(v);}}}}}system("pause");return 0;
}

Codeforces Round #783 (Div. 2) A-F相关推荐

  1. Codeforces Round #783 (Div. 2)和Codeforces Round #784 (Div. 4)---- ABC | ABCDEF

    目录 Codeforces Round #783 (Div. 2) A B C Codeforces Round #784 (Div. 4) A B C D E F Codeforces Round ...

  2. Codeforces Round #797 (Div. 3)无F

    Codeforces Round #797 (Div. 3)无F 这打的也太屎了,白天把G补了才知道简单的很,但f还是没头绪呜呜呜 Problem - A - Codeforces Given the ...

  3. Codeforces Round #701 (Div. 2) A ~ F ,6题全,超高质量良心题解【每日亿题】2021/2/13

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 A - Add and Divide B - Replace and Keep Sorted C ...

  4. Codeforces Round #506 (Div. 3) 1029 F. Multicolored Markers

    CF-1029F 题意: a,b个小正方形构造一个矩形,大小为(a+b),并且要求其中要么a个小正方形是矩形,要么b个小正方形是矩形. 思路: 之前在想要分a,b是否为奇数讨论,后来发现根本不需要.只 ...

  5. Codeforces Round #827 (Div. 4) D - F

    D. Coprime time limit per test 3 seconds memory limit per test 256 megabytes input standard input ou ...

  6. Educational Codeforces Round 110 div.2 A~F题解

    视频讲解:BV1254y137Rn A. Fair Playoff 题目大意 有 444 位选手参加比赛,第 iii 位选手的水平为 si(1≤si≤100)s_i(1 \leq s_i \leq 1 ...

  7. Codeforces Round #783 (Div. 2) ABC

    自从上个月得了麦粒肿,又遇上入D的一系列麻烦事儿,心态爆炸,状态开始摆烂,摆完蓝桥杯,摆完昆明站,终于在这几天感觉状态逐渐好转... 冲冲冲! ​​​​​​​​​​​Problem - A - Cod ...

  8. Codeforces Round #712 Div.2(A ~ F) 超高质量题解(每日训练 Day.15 )

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Codeforces Round #712 Div.2(A ~ F) 题解 比赛链接:https:// ...

  9. Codeforces Round #699 (Div. 2) F - AB Tree(贪心、树上DP)超级清晰,良心题解,看不懂来打我 ~

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Codeforces Round #699 (Div. 2) F - AB Tree Problem ...

最新文章

  1. java应用窗口大小_java 如何让程序窗口随屏幕大小改变 | 学步园
  2. spring集成rabbitmq遇到的问题
  3. Linux文本过滤与处理命令
  4. SMTP身份验证(LOGIN、PLAIN、CRAM-MD5)
  5. 我的第一个Windows Phone 7应用程序
  6. 【数据竞赛】5行代码提升GBDT,提升巨大!
  7. atitit.orm的缺点与orm框架市场占有率,选型attilax总结
  8. LeetCode 1568. 使陆地分离的最少天数(DFS)
  9. 大数据学习笔记02:在私有云上创建与配置虚拟机
  10. 【日常水题-bfs】马的遍历
  11. 【渝粤题库】陕西师范大学164105 物流管理学 作业(高起专)
  12. python动态是什么意思_怎么看出自己是Python什么阶段
  13. java 下载 名乱码_java下载文件中文文件名乱码
  14. 332.重新安排行程
  15. MyCms 活码二维码(动态二维码)源码版介绍
  16. 刘万祥老师讲如何利用条件格式色阶制作数据地图
  17. vscode markdown preview enhanced css font
  18. git和github使用
  19. Selenium 设置代理chrome
  20. vue实现页面全屏和退出全屏

热门文章

  1. 8、软硬车厢交替排列——Queue(java数据结构)
  2. 数据中心的双活与灾备方案设计
  3. ora-3136故障处理
  4. 使用samba服务在Linux与Windows直接共享文件夹,海康威视网络摄像头录像视频存储到ubuntu服务器
  5. 电脑维护入门 GHOST 使用方法 图解说明
  6. Emerging Threats rules suricata规则功能介绍
  7. 利用循环输出如下图形
  8. 从外网访问内网服务器
  9. 怎么让两个java文件关联,怎么把多个excel文件合并成一个【几个excle合并成一个】...
  10. linux 多个csv合并成一个csv