计蒜客)翻硬币

//暴力匹配

#include<cstdio>
#include<cstring>
#define CLR(a, b) memset((a), (b), sizeof((a)))
using namespace std;
int n, m, t;
int main() {
int i, j, x;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
int g[n][m];
CLR(g, );
for(i = ; i < n; ++i) {
for(j = ; j < m; ++j) {
scanf("%d", &g[i][j]);
}
}
int f = ;
bool mk = ;
for(i = ; i < n && f; ++i) {
mk = g[i][] != g[][];
for(j = ; j < m && f; ++j) {
if(g[i][j] != g[][j] ^ mk) {
f = ;
}
}
}
puts(f ? "YES" : "NO");
}
}

Educational Codeforces Round 18

codeforces 792A - New Bus Route

官方题解

At first let's notice that if there exists such triple ai, aj and ak that ai < aj < ak, then |ak - ai| > |aj - ai| and |ak - ai| > |ak - aj|.

Thus we can sort all numbers and check only adjacent ones. There are exactly n - 1 of such pairs. The only thing left is to find minimal distance of all pairs and count pairs with that distance.

Overall complexity: O(n logn)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const ll inf = 2e9+;
int n;
int a[];
int main() {
scanf("%d", &n);
int i, j;
for(i = ; i < n; ++i)
scanf("%d", &a[i]);
sort(a, a+n);
ll ans = inf;
ll cnt = , t;
for(i = ; i < n; ++i) {
t = abs(a[i] - a[i-]);
if(t < ans) { ans = t; cnt = ; }
else if(t == ans) cnt++;
}
printf("%I64d %I64d\n", ans, cnt);
}
/*
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const ll inf = 2e9+5;
const int N = 2e5+5;
int n, k;
int ans;
ll a[N];
ll c[N][3];
void init(ll n, ll m) {
ll i, j;
memset(c,0,sizeof(c));
for(i = 0; i <= m; i++)
c[0][i] = c[1][i] = 1;
for(i = 0; i <= m; i++)
c[i][i] = 1;
for(i = 0; i <= n; i++)
c[i][0] = 1;
for(i = 1; i <= n; i++)
{
for(j = 1; j <= m; j++)
{
if(i != j)
c[i][j] = (c[i-1][j] + c[i-1][j-1]);
}
}
}
int main() {
init(N-1, 2);
scanf("%d", &n);
int i, j;
ll mi = inf;
ll cnt = 0;
for(i = 0; i < n; ++i) scanf("%I64d", &a[i]);
sort(a, a+n);
for(i = 1; i < n; ++i) {
ll x = a[i] - a[i-1];
if(x < mi) mi = x;
}
ll ss = 0, s = 0;
for(i = 1; i < n; ++i) {
cnt = 0;
if(a[i] == a[i-1]) {
while(a[i] == a[i-1] && i < n) {cnt++;i++;}
s = c[cnt+1][2];
ss += s;
}
else if(a[i] - a[i-1] == mi) ss++;
}
printf("%I64d %I64d\n", mi, ss);
return 0;
}
*/

codeforces 792B - Counting-out Rhyme

官方题解:The task was just about implementing algorithm described in statement.

This is one of many possible ways of doing this. Firstly you should notice that doing ai iterations in i-th step is equal to doing ai mod (n - i) iterations (0-based numbering). That is less than n.

Now fill array of length n with ones and create pointer to current leader. Then on i-th step move pointer to the right (from cell n - 1 proceed to 0) till you encounter ai mod (n - i) ones. When finished, write 0 to this cell and move pointer to next cell which contains 1.

Overall complexity: O(n2).

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
#define lson rt*2
#define rson rt*2+1
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const ll inf = 2e9+;
const int N = 2e5+;
int n, k;
int ans;
vector <int > ve;
int main() {
scanf("%d%d", &n, &k);
int i, x;
for(i = ; i <= n; ++i) ve.push_back(i);
int t = ;
for(i = ; i < k; ++i, n--) {
scanf("%d", &x);
t = (t+x) % n;
printf("%d ", ve[t]);
ve.erase(ve.begin() + t);
}
return ;
}

codeforces 792C. Divide by Three

官方题解:

Let's declare a function which takes number as a string and erases minimal number of digits in substring from 2-nd to last character to obtain beautiful number.

Note that if the answer for given string exists, then this function will erase no more than 2 digits. If the number is divisible by 3 then sum of its digits is also divisible by 3. So here are the only options for the function:

  • Sum of digits is already equal to 0 modulo 3. Thus you don't have to erase any digits.
  • There exists such a digit that equals sum modulo 3. Then you just have to erase this digit.
  • All of the digits are neither divisible by 3, nor equal to sum modulo 3. So two of such digits will sum up to number, which equals sum modulo 3 ((2 + 2) mod 3 = 1, (1 + 1) mod 3 = 2).

Let positions of non-zero numbers be a1, a2, ..., ak. Then you can easily see that its enough to check only three function outputs: on substrings [a1..n], [a2..n] и [a3..n]. We imply that all digits to the left of the taken non-zero digit are erased. As we can erase no more than 2 digits, these options will cover all the cases.

If there exists no answer for any of substrings, than you need to check if the number contains 0 — it will be answer in that case. If there is no 0, then answer is  - 1.

Otherwise the answer is the function output of maximal length.

Overall complexity: O(n).

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+;
string a, b, c;
int ss(string d) {
int len = d.length();
int sum = ;
for(int i = ; i < len; ++i)
sum = (sum + d[i] - '') % ;
return sum | !d.length();//进行删除数字之后,可能删光了,比如11,删去两次 1
}
void change(string & r) {
while(r[] == '' && r.length() > )
r.erase(, );//进行删除之后,判断并删去前导零
}
int main(){
cin >> a;
int x = ss(a);
int y = - x;
int s1 = , s2 = ;
b = c = a;
for(int i = a.length() - ; i >= ; --i) {
if((a[i] - '') % == x && s1) { b.erase(i, ); s1--; }
if((a[i] - '') % == y && s2) { c.erase(i, ); s2--; }
}
change(b); change(c);
s1 = ss(b); s2 = ss(c);
if(s1 && s2) puts("-1");
else {
if(c.length() > b.length() && !s2 || s1)
b = c;
cout << b << endl;
}
}

codeforces 792 D. Paths in a Complete Binary Tree

官方题解:

In this editorial x represents the number of vertex we are currently in.

Let k be the maximum integer number such that x is divisible by 2k (or the number of zeroes at the end of the binary representation of x). It is easy to prove that if k = 0, then x is a leaf; if k = 1, then both children of x are leaves, and so on. Even more, the difference between x and any of his children is exactly 2k - 1. So to traverse to the left child, we have to subtract 2k - 1 from x (if x is not a leaf), and to traverse to the right child, we add 2k - 1 to x.

How can we process traversions up? Let y be the number of the parent node. y has exactly k + 1 zeroes at the end of its binary representation, so to traverse from y to x, we need to either add or subtract 2k from y. And to traverse from x to y we also have to either subtract or add 2k to x. One of these operations will lead us to the number divisible by 2k + 1 and not divisible by 2k + 2, and we need to choose this operation.

Time complexity is .

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+;
ll n, q, u, x, y;
char s[N];
int main(){
scanf("%I64d%I64d", &n, &q);
while(q--) {
scanf("%I64d ", &u);
scanf("%s", s);
int len = strlen(s);
for(int i = ; i < len; ++i) {
if(s[i] == 'U') {
if(u != (n+)/) {
x = u & (-u);
y = (u-x) & (x-u);
if((x << ) < y || !y)
u += x;
else u -= x;
//100:4 , 1000:8 , 1100:12
//4: x = 4, y = 0
//12: x = 4, y = 8
//U(4 或 12) = 8;
//我就打个草稿orz
//5: x = 1, y = 4
//7: x = 1, y = 2
//U(5 或 7) = 6;
}
}
else if(s[i] == 'L') {
if(u % == ) {
x = u >> ;
u -= x & (-x);
}
}
else {
if(u % == ) {
x = u >> ;
u += x & (-x);
}
}
}
printf("%I64d\n", u);
}
}

codeforces 792 E. Colored Balls

官方题解:

If we want to divide all balls from some box into k sets with sizes x and x + 1 (and there are ai balls in this box), then either or . So the solution will be like that:

  1. Iterate over the possible sizes of sets x (from 1 to , or to some constant — in our solution it's 40000) and check if we can divide all balls into sets with sizes x and x + 1,
  2. Then iterate over the number of sets k, calculate the sizes of sets if we want to divide the first box exactly into k sets and try to divide balls from all other boxes into sets of these sizes.

If we want to divide ai balls from the same box into k sets, then the sizes will be and ; but if , then we also have to check if sizes can be and .

If we fix sizes x and x + 1 and we want to check whether we can divide a box with ai balls into sets with these sizes (and to get the minimum possible number of such sets), then the best option will be to take sets. If , then such division is possible. If not, then it's impossible to divide ai balls into sets of x and x + 1 balls.

Time complexity of this solution is .

要么k个盒子要么放X个,k*x≤a[i],枚举x,k在1~根号a,直接枚举情况重复,去掉重复就是根号a了,枚举的情况看注释、、、

//orz

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+;
int a[];
int n;
ll ans;
bool ff(int c) {
int f = c - ;
if(f <= ) return false;
ll cnt = ;
for(int j = ; j < n; ++j) {
if(a[j] / f >= a[j] % f) {
int x = a[j] / c;
int y = a[j] % c;
cnt += x;
if(!y) continue;
if(f - y <= x) {
cnt++; continue;
}
return false;
}
else
return false;
}
ans = min(ans, cnt);
return true;
}
int main() {
int mi = inf;
scanf("%d", &n);
ans = ;
int i, j;
for(i = ; i < n; ++i) {
scanf("%d", &a[i]);
if(a[i] < mi) mi = a[i];
ans += a[i];
}
int l = ceil(sqrt(mi)) + ;
for(i = ; i <= l; ++i) {//枚举盒子数以及放的个数
if(i != ) ff(i); // i , i-1
ff(mi / i); // m/i , m/i-1
ff(mi/i + ); // m/i+1 , m/i
}
printf("%I64d\n", ans);
return ;
}

Codeforces Round #407(Div.2)

codeforces789 A. Anastasia and pebbles

官方题解: For every pebble type we can count the minimal number of pockets Anastasia need to collect all pebbles of this type. That's easy to notice that this number equals . So the answer for the problem is . Solution complexity is O(N).

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+;
int n, m, k, ans = ;
int main(){
scanf("%d%d", &n, &k);
while(n--){
scanf("%d", &m);
ans += (m + k - ) / k;
}
    printf("%d\n", (ans + ) /  );
}

codeforces 789 B. Masha and geometric depression

官方题解:

We need to handle following cases in the solution:

  1. |b1| > l — answer is 0.
  2. b1 = 0 — if 0 is present in array a than answer is 0, else inf.
  3. q = 1 — if b1 is present in array a than answer is 0, else inf.
  4. q =  - 1 — if both b1 and  - b1 are present in array a than answer is 0, otherwise inf.
  5. q = 0 — if 0 isn't present in array a than answer is inf, else if b1 is present in a than answer is 0, else answer is 1.
  6. In all other cases we can simply iterate over all terms of progression b while their absolute value doesn't exceed l. For every term that is not present in a we simply increasing answer by 1. Obviously, the absolute value of every next element is bigger in at least 2 times than the absolute value of previous. That's why we'll need to check at most log l progression terms.

Solution complexity is O(M·logL) or O(M·logM + logL·logM).

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+;
ll b1, q, l, m;
map<int, int > mp;
int main(){
scanf("%I64d%I64d%I64d%I64d", &b1, &q, &l, &m);
int i, j, ans = , x;
for(i = ; i < m; ++i) {
scanf("%d", &x);
mp[x] = ;
}
for(i = ; i < ; ++i) {
if(abs(b1) > l) break;
if(!mp[b1]) ans++;
b1 *= q;
}
if(ans >= ) puts("inf");//见下面第二个样例~
else printf("%d\n", ans);
}
/*
123 0 21 4
543453 -123 6 1424
inf 123 -1 2143435 5
-123 0 12 5 -11245
inf 11 0 228 5
-1 -17 1 5 -11245
inf
*/

codeforces 789 C. Functions again  【前缀和】

官方题解:

We can solve the problem for segments with odd and even l separately. Let's build arrays b (bi = |ai + 1 - ai|·( - 1)i) and c (ci = |ai + 1 - ai|·( - 1)i + 1). Obviously, that segment with the greatest sum in array b starts in some even index. In every segment starting in odd index we can move l one position right and make answer not-worse, because every element of odd index in b is non-positive. Also, sum of segment starting in even index of b equals to value of f on the same segment. Analogically for array c and odd starting indexes. So the answer equals to maximal of maximal sums of arrays b and c.

The segment with the greatest sum can be found with the two pointers method or using prefix sums. Such solution works with O(N) complexity.

//yy:求前缀和,求正的最大值和负的最小值,相减即为答案orz。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+;
int n;
int main(){
scanf("%d", &n);
int x, y;
ll ma = , mi = , d;
ll s = ;
scanf("%d", &x);
for(int i = ; i < n; ++i) {
scanf("%d", &y);
d = abs(x - y);
if(i % == ) d *= -;
s += d;
if(s > ma) ma = s;
if(s < mi) mi = s;
x = y;
}
printf("%I64d\n", ma - mi);
}

codeforces 789 D. Weird journey

官方题解:

We can consider the system of towns and roads as a graph, where edges correspond to roads and vertexes to cities.

Now, let's fix two edges, that will be visited once. All other edges we can split into two. Then, the good way in the old graph equivalents to any Euler path in the computed one. Widely known that Euler path exists in graph when and only when there are 0 or 2 vertexes with odd degree. Consider following cases of mutual placement of edges that will be visited once:

  • Regular(not loops) edges that are not adjacent — graph has four vertexes with odd degree, so Euler path doesn't exist.
  • Regular edges that are adjacent — graph has exactly two vertexes with odd degree, so Euler path exists. So, any pair of adjacent regular edges satisfies Igor.
  • One of the edges is a loop — graph hasn't any vertex with the odd degree(if another chosen edge is a loop too) or has two of them(if another chosen edge is regular). So, any pair in which at least one edge is a loop satisfies Igor.

So, we have to calculate the number of pairs of adjacent regular edges and add the answer for loops. For every vertex i we can calculate cnti — the number of regular edges incoming in it. General number of adjacent regular edges is . Also, we need to add the number of pairs with loops. Let's count loop — general number of loops in the graph. So we can add loop·(n - 1) to the answer. Now, we included pairs with two loops twice. That's why we need to subtract Cloop2 — the number of pairs with two loops.

Also, we need to check the graph to be connected by edges. If the graph is not connected then the answer is 0. We can do it using algorithms of DFS or BFS.

Complexity of the given solution if O(N + M).

待补。。。。。。。

其他学习:2-sat问题

入门学习:http://blog.csdn.net/pi9nc/article/details/11849843

回忆:关键词:对称、环、极大强连通子图、拓扑排序、satisfiability

问对于一个合取范式,是否有一种输入使得他的输出是1,具体点就是类似这样的布尔表达式(x1 or x2 or x3)and(x3 or x4)and(not x1 or x5)对于所有的x是否有一种01取值,使得最后的结果是1。而2-sat问题就是每一个由or连接的子式都只包含两个变量,比如这样(x1 or x2) and (not x3 or x1)   

1)   hdu1814 Peaceful Commission 【2-SAT】[染色法]

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
#define lson rt*2
#define rson rt*2+1
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = ;
const int M = ;
struct Edge {
int to, next;
}edge[M];
int head[N], tot;
void init() {
tot = ;
CLR(head, -);
}
void addedge(int u, int v) {
edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++;
}
bool vis[N];//染色标记,为true表示选择
int S[N], top;//栈
bool dfs(int u) {
if(vis[u^]) return false;
if(vis[u]) return true;
vis[u] = true;
S[top++] = u;
for(int i = head[u]; i != -; i = edge[i].next)
if(!dfs(edge[i].to))
return false;
return true;
}
bool Twosat(int n) {
memset(vis, false, sizeof(vis));
for(int i = ; i < n; i += ) {
if(vis[i] || vis[i^]) continue;
top = ;
if(!dfs(i)) {
while(top) vis[S[--top]] = false;
if(!dfs(i^)) return false;
}
}
return true;
}
int main() {
int n, m;
int u, v;
while(scanf("%d%d", &n, &m) == ) {
init();
while(m--) {
scanf("%d%d", &u, &v);
u--; v--;
addedge(u, v^);
addedge(v, u^);
}
if(Twosat(*n)) {
for(int i = ;i < *n; i++)
if(vis[i])
printf("%d\n", i+);
}
else printf("NIE\n");
}
return ;
}

其他 待补。。。

3.26-3.31【cf补题+其他】的更多相关文章

  1. 【cf补题记录】Codeforces Round #608 (Div. 2)

    比赛传送门 再次改下写博客的格式,以锻炼自己码字能力 A. Suits 题意:有四种材料,第一套西装需要 \(a\).\(d\) 各一件,卖 \(e\) 块:第二套西装需要 \(b\).\(c\).\ ...

  2. 【cf补题记录】Codeforces Round #607 (Div. 2)

    比赛传送门 这里推荐一位dalao的博客-- https://www.cnblogs.com/KisekiPurin2019/ A:字符串 B:贪心 A // https://codeforces.c ...

  3. 【cf补题记录】A. Hotelier

    思考之后再看题解,是与别人灵魂之间的沟通与碰撞 A. Hotelier 题意 给出长度为n的字符串,字符串由'L'.'R'以及数字0~9组成.旅馆有10间房子,L代表客人从左边入住,R代表客人从右边入 ...

  4. 2020.12.20vj补题

    A - Insomnia cure 题意:一共s只龙,每隔k,l,m,n只龙就会受伤,问这s只龙有多少龙是受伤的 思路:看起来题目范围并不是很多,直接进行循环判断 代码: 1 #include< ...

  5. 4.30-5.1cf补题

    //yy:拒绝转载!!! 悄悄告诉你,做题累了,去打两把斗地主就能恢复了喔~~~ //yy:可是我不会斗地主吖("'▽'") ~~~那就听两遍小苹果嘛~~~ 五一假期除了花时间建模 ...

  6. 【春训团队赛第四场】补题 | MST上倍增 | LCA | DAG上最长路 | 思维 | 素数筛 | 找规律 | 计几 | 背包 | 并查集

    春训团队赛第四场 ID A B C D E F G H I J K L M AC O O O O O O O O O 补题 ? ? O O 传送门 题目链接(CF Gym102021) 题解链接(pd ...

  7. 【补题记录】ZJU-ICPC Summer Training 2020 部分补题记录

    补题地址:https://zjusummer.contest.codeforces.com/ Contents ZJU-ICPC Summer 2020 Contest 1 by Group A Pr ...

  8. hdu5017:补题系列之西安网络赛1011

    补题系列之西安网络赛1011 题目大意:给定一个椭球: 求它到原点的最短距离. 思路: 对于一个椭球的标准方程 x^2/a^2 + y^2/b^2 +z^2/c^2=1 来说,它到原点的最短距离即为m ...

  9. 2017河工大校赛补题CGH and 赛后小结

    网页设计课上实在无聊,便开始补题,发现比赛时候僵着的东西突然相通了不少 首先,"追妹"这题,两个队友讨论半天,分好多种情况最后放弃(可是我连题目都没看啊),今天看了之后试试是不是直 ...

随机推荐

  1. DBUtils工具类的使用

    DBUtils工具类1.DBUtils工具类,由apache组织提供的工具类,对JDBC做了一些简单封装. 做了查询的封装,把查询的结果封装到List集合 Map集合 JavaBean对象中 做了增删 ...

  2. luajit+nginx+上传模块+lua模块编译安装

    git clone https://github.com/fdintino/nginx-upload-module.git git clone https://github.com/openresty ...

  3. bzoj 3064: Tyvj 1518 CPU监控

    Description 1.区间加 \(z\) 2.区间覆盖为 \(z\) 3.查询区间最大值 4.查询区间历史最大值 Solution 线段树维护历史最值,思想大致是维护标记出现过的最大值 考虑这种 ...

  4. npm proxy报错处理

    npm经常抽风,动不动安装一个模块就这样了: 提示是否设置了正确的代理地址,解决方法网上有很多,有说取消代理.重新设置代理等等,最简单粗暴解决: 删除nodejs安装路径下面的npmrc文件,再使用淘 ...

  5. 二:Redis数据类型

    一.nosql(非关系性数据库): mongoDB hbase redis nulch hive pig mahout zookeeper 二:redis 数据类型 1.存储string: 常用命令 ...

  6. springboot遇到的那些坑

    一.在springboot整合jsp时,程序中的所有配置都是正确的,但是在启动springboot后,访问无法找到jsp页面,报错404, 解决办法 二.在springboot整合jpa实现crud时 ...

  7. 设计模式入门,单件模式,c++代码实现

    // test05.cpp : Defines the entry point for the console application.// #include "stdafx.h" ...

  8. PAT 1048. Find Coins

    two sum题目,算是贪婪吧 #include <cstdio> #include <cstdlib> #include <vector> #include &l ...

  9. 移动端布局注意事项与less

    用Koala实现less的实时编译 1.下载Koala(Koala可以实现实时编译) 2.把CSS文件夹(如index.css,index.less)拖到Koala中 3.点击到需要编译的index. ...

  10. vim的日常使用

    Esc 退出编辑模式,输入一下命令 :wq保存后退出 :wq!强制保存后退出 :w保存但不退出 :w!若文件为只读,强制保存 :q不保存退出 :q!不保存强制退出 :e!将文档还原到最原始状态