HNOI2018

寻宝游戏(位运算、基数排序)

看到位运算就要按位考虑。二进制下,\(\land 1\)与\(\lor 0\)没有意义的,\(\land 0\)强制这一位变为\(0\),\(\lor 1\)强制这一位变为\(1\)

那么如果某一位的答案要为\(0\),也就意味着:要么同时不存在\(\land 0\)与\(\lor 1\),要么最后一个\(\land 0\)后面不能有\(\lor 1\)。答案为\(1\)同理。

那么对于每一位,将所有\(a_i\)在这一位上的值从右往左看作一个二进制数\(x\),将操作序列\(\land\)对应为\(1\)、\(\lor\)对应为\(0\),从右往左看作一个二进制数\(op\),那么如果答案的这一位为\(0\),必须满足\(op \geq x\)。反之则要满足\(op < x\)。

那么最后的答案就会表现为\(a \leq op < b\)的形式,答案为\(\min\{b-a , 0\}\)。

那么将\(x\)排序,每一次扫一遍找到\(a\)和\(b\)就可以了。注意到给出这\(m\)个数的顺序正好是从低位到高位依次给出,所以可以基数排序。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
//This code is written by Itst
using namespace std; const int MOD = 1e9 + 7;
int srt[5007] , val[5007] , tmp[5007] , pot[3];
int N , M , Q;
char s[5007]; int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
scanf("%d %d %d" , &N , &M , &Q);
for(int i = 1 ; i <= M ; ++i)
srt[i] = i;
int times = 1;
for(int i = 1 ; i <= N ; ++i){
pot[0] = pot[1] = 0;
scanf("%s" , s + 1);
for(int j = 1 ; j <= M ; ++j){
++pot[s[j] - 47];
if(s[j] - 48)
val[j] = (val[j] + times) % MOD;
}
for(int j = 1 ; j <= M ; ++j)
tmp[++pot[s[srt[j]] - 48]] = srt[j];
memcpy(srt , tmp , sizeof(tmp));
times = times * 2 % MOD;
}
srt[M + 1] = M + 1;
val[M + 1] = times;
while(Q--){
scanf("%s" , s + 1);
int L = 0 , R = M + 1;
for(int i = 1 ; i <= M ; ++i)
if(s[srt[i]] == '1'){
R = i;
break;
}
for(int i = M ; i ; --i)
if(s[srt[i]] == '0'){
L = i;
break;
}
if(L > R)
puts("0");
else
printf("%d\n" , (val[srt[R]] - val[srt[L]] + MOD) % MOD);
}
return 0;
}

转盘(线段树、单调栈)

毫无疑问要断环成链,那么我们要求的就是\(\min\limits_{i=1}^N\{ \max\limits_{j=0}^{N - 1} \{ a_{j+i} + (N - 1 - j)\} \}\),即\(\min\limits_{i=1}^N \{\max\limits_{j=i}^{N+i-1}\{ a_{j} - j \} + i \} + N - 1\)

所以要算\(\min\limits_{i=1}^N \{\max\limits_{j=i}^{N+i-1}\{ a_{j} - j \} + i \}\)。因为\(a_j - j > a_{j+N} - (j+N)\),所以原式等于\(\min\limits_{i=1}^N \{\max\limits_{j=i}^{2N}\{ a_{j} - j \} + i \}\)。如果\(a_j - j\)有贡献,它一定是后缀最大值,而所有后缀最大值构成的是一个单调栈。对于单调栈中的第\(k\)个元素的位置\(L_k\),我们要求\(\min\limits_{i=L_{k-1} + 1}^N \{ a_{L_k} - L_k + i \}\),显然\(i = L_{k-1}+1\)时有最小值。

所以如果只有\(1\)次询问,可以维护一个单调栈,对于栈内每一个元素找到它之前的最后一个比它大的元素的位置,\(+1\)之后就是它能取到的区间中最左的左端点。

然后考虑修改。不难想到使用线段树维护单调栈(基础实现见楼房重建

对于线段树上每一个点维护单调栈的最大值和答案。线段树上每一个点维护的答案是:对于左儿子传上来的单调栈\(L_1,L_2,...,L_k\),左端点为\(L_1+1,L_2+1,...,L_k+1\)的区间的答案。

每一次合并左右儿子时,因为右半部分一定会是当前单调栈的一部分,所以拿右儿子的最大值\(max\)放在左儿子上二分得到左儿子传上来的单调栈。

如果当前节点的右儿子的最大值\(> max\),意味着当前点维护的单调栈的左儿子传上来的部分一定也是现在正在寻找的栈的一部分,直接把答案拿过来然后递归右儿子,否则递归左儿子。到叶子节点意味着找到了\(L_k\),记得计算一次左端点为\(L_k+1\)时的答案。

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
//This code is written by Itst
using namespace std; inline int read(){
int a = 0;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
} const int MAXN = 1e5 + 7;
struct node{
int rgL , rgR , maxN , ans;
}Tree[MAXN << 3];
int val[MAXN << 1] , N , M , P; #define lch (x << 1)
#define rch (x << 1 | 1)
#define mid ((l + r) >> 1)
#define PII pair < int , int > int find(int x , int dir){
if(Tree[x].rgL == Tree[x].rgR)
return Tree[x].rgL + dir + 1;
if(Tree[rch].maxN > dir)
return min(Tree[x].ans , find(rch , dir));
return find(lch , dir);
} inline void pushup(int x){
Tree[x].maxN = max(Tree[rch].maxN , Tree[lch].maxN);
Tree[x].ans = find(lch , Tree[rch].maxN);
} void init(int x , int l , int r){
Tree[x].rgL = l;
Tree[x].rgR = r;
Tree[x].ans = 0x7fffffff;
if(l == r)
Tree[x].maxN = val[l] - l;
else{
init(lch , l , mid);
init(rch , mid + 1 , r);
pushup(x);
}
} void modify(int x , int l , int r , int tar){
if(l == r){
Tree[x].maxN = val[tar] - tar;
return;
}
if(mid >= tar)
modify(lch , l , mid , tar);
else
modify(rch , mid + 1 , r , tar);
pushup(x);
} int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
N = read(); M = read(); P = read();
for(int i = 1 ; i <= N ; ++i)
val[i] = val[i + N] = read();
init(1 , 1 , N << 1);
int lastans = Tree[1].ans + N - 1;
cout << lastans << '\n';
for(int i = 1 ; i <= M ; ++i){
int x = P ? read() ^ lastans : read() , y = P ? read() ^ lastans : read();
val[x] = val[x + N] = y;
modify(1 , 1 , N << 1 , x);
modify(1 , 1 , N << 1 , x + N);
cout << (lastans = Tree[1].ans + N - 1) << '\n';
}
return 0;
}

毒瘤(虚树)

如果\(m=n-1\)就是简单的树的独立集个数统计问题,直接树形DP即可;但是相比于树上独立集,这里多了\(11\)条约束。

注意到\(11\)比较小,可以暴力枚举。对于每一条边的两个端点有\((0,1),(0,0),(1,0)\)(\(1\)表示选,\(0\)表示不选)三种情况,而\((0,0),(0,1)\)两种情况可以合成一种,即只确定其中一端不选,另一端不做限制。所以一条边只有两种情况,所以可以\(2^{11}\)地枚举每条边的状态,每一次都在树上DP求一遍独立集个数。

考虑如何优化。注意到每一次只有\(22\)个点的状态会发生变化,故将这\(22\)个点拿出来建立虚树。对于虚树上的每一条边求出其转移系数。求转移系数的方式就是在原树上暴跳父亲,每一次把没有关键点的子树直接拿过来合并。求转移系数对应下面代码里的calc函数部分

#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<vector>
#include<cmath>
//This code is written by Itst
using namespace std; inline int read(){
int a = 0;
char c = getchar();
while(!isdigit(c))
c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
} const int MAXN = 1e5 + 13 , MOD = 998244353;
struct Edge{
int end , upEd;
}Ed[MAXN << 1];
int head[MAXN] , DP[MAXN][2] , dep[MAXN] , dfn[MAXN] , jmp[MAXN][19];
int N , M , cntEd = 1 , cnt , ts , mr[21]; inline void addEd(int a , int b){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
} #define go(a , b , c) (a = 1ll * a * (b + c) % MOD)
void dfs(int x , int p){
dep[x] = dep[p] + 1;
dfn[x] = ++ts;
jmp[x][0] = p;
for(int i = 1 ; i <= 16 ; ++i)
jmp[x][i] = jmp[jmp[x][i - 1]][i - 1];
DP[x][0] = DP[x][1] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != p)
if(!dep[Ed[i].end]){
dfs(Ed[i].end , x);
go(DP[x][0] , DP[Ed[i].end][0] , DP[Ed[i].end][1]);
DP[x][1] = 1ll * DP[x][1] * DP[Ed[i].end][0] % MOD;
}
else
if(dep[Ed[i].end] > dep[x])
mr[++cnt] = i;
} bool cmp(int a , int b) {return dfn[a] < dfn[b];} inline int LCA(int x , int y){
if(dep[x] < dep[y])
x ^= y ^= x ^= y;
for(int i = 16 ; i >= 0 ; --i)
if(dep[x] - (1 << i) >= dep[y])
x = jmp[x][i];
if(x == y)
return x;
for(int i = 16 ; i >= 0 ; --i)
if(jmp[x][i] != jmp[y][i]){
x = jmp[x][i];
y = jmp[y][i];
}
return jmp[x][0];
} #define pb push_back
#define add(a , b) (a + b >= MOD ? a + b - MOD : a + b)
vector < int > ch[MAXN] , nd;
int dp[MAXN][2] , xs[MAXN][2][2] , st[101] , top , cntN;
bool mrk[MAXN]; void calc(int x){
xs[x][0][0] = xs[x][1][1] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(!mrk[Ed[i].end] && jmp[Ed[i].end][0] == x){
go(xs[x][0][0] , DP[Ed[i].end][1] , DP[Ed[i].end][0]);
xs[x][1][1] = 1ll * xs[x][1][1] * DP[Ed[i].end][0] % MOD;
}
int p = x;
while(!mrk[jmp[p][0]] && jmp[p][0]){
mrk[p = jmp[p][0]] = 1;
int P = xs[x][0][0] , Q = xs[x][0][1];
xs[x][0][0] = add(P , xs[x][1][0]);
xs[x][0][1] = add(Q , xs[x][1][1]);
xs[x][1][0] = P;
xs[x][1][1] = Q;
for(int i = head[p] ; i ; i = Ed[i].upEd)
if(jmp[Ed[i].end][0] == p && !mrk[Ed[i].end]){
go(xs[x][0][0] , DP[Ed[i].end][1] , DP[Ed[i].end][0]);
go(xs[x][0][1] , DP[Ed[i].end][1] , DP[Ed[i].end][0]);
xs[x][1][0] = 1ll * xs[x][1][0] * DP[Ed[i].end][0] % MOD;
xs[x][1][1] = 1ll * xs[x][1][1] * DP[Ed[i].end][0] % MOD;
}
}
} void DFS(int x){
mrk[x] = 1;
for(int i = 0 ; i < ch[x].size() ; ++i)
DFS(ch[x][i]);
calc(x);
} void init(){
nd.pb(1);
for(int i = 1 ; i <= cnt ; ++i){
nd.pb(Ed[mr[i]].end);
nd.pb(Ed[mr[i] ^ 1].end);
}
sort(nd.begin() , nd.end() , cmp);
cntN = unique(nd.begin() , nd.end()) - nd.begin();
for(int i = 0 ; i < cntN ; ++i){
if(top){
int t = LCA(st[top] , nd[i]);
while(top - 1 && dep[t] <= dep[st[top - 1]]){
ch[st[top - 1]].pb(st[top]);
--top;
}
if(dep[t] < dep[st[top]]){
ch[t].pb(st[top]);
st[top] = t;
}
}
st[++top] = nd[i];
}
while(top - 1){
ch[st[top - 1]].pb(st[top]);
--top;
}
DFS(1);
} int sum , zt[MAXN];
void getans(int x){
dp[x][0] = zt[x] == 0 || zt[x] == 1;
dp[x][1] = zt[x] == 0 || zt[x] == 2;
for(int i = 0 ; i < ch[x].size() ; ++i){
getans(ch[x][i]);
go(dp[x][0] , dp[ch[x][i]][0] , dp[ch[x][i]][1]);
dp[x][1] = 1ll * dp[x][1] * dp[ch[x][i]][0] % MOD;
dp[ch[x][i]][0] = dp[ch[x][i]][1] = 0;
}
int p = dp[x][0] , q = dp[x][1];
dp[x][0] = (1ll * xs[x][0][0] * p + 1ll * xs[x][0][1] * q) % MOD;
dp[x][1] = (1ll * xs[x][1][0] * p + 1ll * xs[x][1][1] * q) % MOD;
} void Dfs(int x){
if(x > cnt){
getans(1);
sum = (0ll + sum + dp[1][0] + dp[1][1]) % MOD;
dp[1][0] = dp[1][1] = 0;
return;
}
int l = Ed[mr[x]].end , r = Ed[mr[x] ^ 1].end , p = zt[l] , q = zt[r];
if((p == 0 || p == 1) && (q == 0 || q == 2)){
zt[l] = 1; zt[r] = 2;
Dfs(x + 1);
zt[l] = p; zt[r] = q;
}
if(q == 0 || q == 1){
zt[r] = 1;
Dfs(x + 1);
zt[r] = q;
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
N = read();
M = read();
for(int i = 1 ; i <= M ; ++i){
int a = read() , b = read();
addEd(a , b);
addEd(b , a);
}
dfs(1 , 0);
init();
Dfs(1);
cout << sum;
return 0;
}

游戏(拓扑排序)

不难想到对于一段中间的门都不需要钥匙的区间缩成一个点,然后预处理每一个点能够到达的左右端点

暴力的思路是每一次暴力向左右拓展

但可以知道:对于门\((x,y)\),如果\(y \leq x\),那么一定是从\(x\)所在区间通过这扇门走向\(x+1\)所在区间,反之亦然。那么若左边的某个区间能够通过这扇门,它一定能够到达\(x+1\)所在区间能够到达的所有区间。所以连边\((x,x+1)\)表示要先拓展\(x+1\),后拓展\(x\)。然后拓扑排序决定拓展顺序,一个个拓展就可以过了。复杂度似乎是线性的。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cmath>
#include<cassert>
//This code is written by Itst
using namespace std; inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c) && c != EOF){
if(c == '-')
f = 1;
c = getchar();
}
if(c == EOF)
exit(0);
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return f ? -a : a;
} const int MAXN = 1e6 + 7;
vector < int > door , ch[MAXN];
int lft[MAXN] , rht[MAXN] , L[MAXN] , R[MAXN] , in[MAXN];
int N , M; inline void add(int x , int y){
++in[y];
ch[x].push_back(y);
} queue < int > q , work;
void TopSort(){
for(int i = 1 ; i <= M ; ++i)
if(!in[i])
q.push(i);
while(!q.empty()){
int t = q.front();
q.pop();
work.push(t);
for(int i = 0 ; i < ch[t].size() ; ++i)
if(!--in[ch[t][i]])
q.push(ch[t][i]);
}
} inline int find(int x){
return lower_bound(door.begin() , door.end() , x) - door.begin();
} inline void calc(int x){
while(L[x] != 1 || door[R[x]] != N){
if(L[x] != 1 && rht[door[L[x] - 1] + 1] && rht[door[L[x] - 1] + 1] <= door[R[x]]){
L[x] = L[L[x] - 1];
continue;
}
if(door[R[x]] != N && lft[door[R[x]]] >= door[L[x] - 1] + 1){
R[x] = R[R[x] + 1];
continue;
}
break;
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
N = read();
M = read();
int Q = read();
for(int i = 1 ; i <= M ; ++i){
int x = read() , y = read();
y <= x ? lft[x] = y : rht[x + 1] = y;
door.push_back(x);
}
++M;
door.push_back(0);
door.push_back(N);
sort(door.begin() , door.end());
for(int i = 1 ; i <= M ; ++i){
L[i] = R[i] = i;
if(rht[door[i - 1] + 1])
add(i - 1 , i);
if(lft[door[i]])
add(i + 1 , i);
}
TopSort();
while(!work.empty()){
calc(work.front());
work.pop();
}
while(Q--){
int l = find(read()) , r = read();
puts(door[L[l] - 1] + 1 <= r && door[R[l]] >= r ? "YES" : "NO");
}
return 0;
}

排列(贪心、并查集)

首先考虑合法排列的限制条件,也就是在排列\(p\)中,对于\(\forall i \in [1,N]\) , \(a_i\)要出现在\(i\)的前面。我们连边\((i,a_i)\),表示\(i\)要在\(a_i\)之后出现。如果存在合法的排列,最后连成的一定是一棵树。

接下来考虑求最大值。有一种比较naive的贪心:每一次都选择当前可以选择的点中最小的。这种贪心策略显然是错的,反例也很好举。

但这似乎能给我们一些启发:对于当前所有点权中最小的数,它一定会在它的父亲被选完之后立即选。那么考虑将它和它的父亲缩成一个点,表示这两个点的选择是连续的。

那么接下来的问题就是缩成的这个点的权值是多少。

不妨设当前所有点权中最小点权对应的点权为\(x\),它的父亲权为\(y\),有另一个点权为\(z\),并且满足\(y\)对应的点和\(z\)对应的点现在都可以选。那么现在有两种决策:1、先选\(y,x\),后选\(z\),权值和为\(y+2x+3z\);2、先选\(z\),后选\(y,x\),权值和为\(z+2y+3x\)

我们需要取更优的,所以只需要比较它们的大小,故同时减去\(x-z\),除以\(2\),那么第一种方案权值为\(\frac{x+y}{2}+2z\),第二种方案权值为\(z + 2\frac{x+y}{2}\)

可以发现之前的两个点\(x,y\)在这个时候可以等价为一个点权为\(\frac{x+y}{2}\)的点。根据这个思路可以得到点权为\(\frac{\text{它所包含的点的点权和}}{\text{它所包含的点的个数}}\)。

那么可以得到一个贪心:每一次选择一个点权最小的点,把它和它父亲合并,可以使用并查集维护合并过程。最后把合并的点拆开计算答案。

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std; inline int read(){
int a = 0;
char c = getchar();
bool f = 0;
while(!isdigit(c)){
if(c == '-')
f = 1;
c = getchar();
}
while(isdigit(c)){
a = (a << 3) + (a << 1) + (c ^ '0');
c = getchar();
}
return f ? -a : a;
} const int MAXN = 5e5 + 10;
struct Edge{
int end , upEd;
}Ed[MAXN << 1];
int head[MAXN] , pre[MAXN << 1] , fa[MAXN << 1] , ch[MAXN << 1][2] , size[MAXN << 1] , cntEd , cntNode , N , t;
long long pri[MAXN << 1] , ans;
bool vis[MAXN] , mark[MAXN << 1];
struct cmp{
bool operator ()(int a , int b){
return pri[a] * size[b] > pri[b] * size[a];
}
};
priority_queue < int , vector < int > , cmp > q; int find(int x){
return fa[x] == x ? x : (fa[x] = find(fa[x]));
} inline void addEd(int a , int b){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
} bool dfs(int x , int p){
pre[x] = p;
vis[x] = 1;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != p)
if(vis[Ed[i].end] || dfs(Ed[i].end , x))
return 1;
return 0;
} void color(int x){
if(x <= N)
ans += t++ * pri[x];
else{
color(ch[x][0]);
color(ch[x][1]);
}
} int main(){
#ifndef ONLINE_JUDGE
freopen("in" , "r" , stdin);
//freopen("out" , "w" , stdout);
#endif
cntNode = N = read();
size[0] = 1;
for(int i = 1 ; i <= N ; ++i){
int a = read();
addEd(a , i);
addEd(i , a);
fa[i] = i;
size[i] = 1;
}
for(int i = 1 ; i <= N ; ++i){
pri[i] = read();
q.push(i);
}
for(int i = 0 ; i <= N ; ++i)
if(!vis[i])
if(dfs(i , -1)){
puts("-1");
return 0;
}
while(!q.empty()){
int t = q.top();
q.pop();
if(mark[t])
continue;
int f = find(pre[t]) , x = ++cntNode;
fa[f] = fa[t] = fa[x] = x;
size[x] = size[f] + size[t];
pri[x] = pri[f] + pri[t];
ch[x][0] = f;
ch[x][1] = t;
pre[x] = pre[f];
mark[t] = mark[f] = 1;
if(pre[x] != -1)
q.push(x);
}
color(cntNode);
cout << ans;
return 0;
}

道路(树形DP)

设\(f_{i,j,k}\)表示从\(1\)号点到\(i\)号点经过了\(j\)条公路、\(k\)条铁路时,\(i\)及其子树的最小不便利值和,从底往上DP,转移枚举修哪一条边。

#include<bits/stdc++.h>
//This code is written by Itst
using namespace std; inline int read(){
int a = 0;
bool f = 0;
char c = getchar();
while(c != EOF && !isdigit(c)){
if(c == '-')
f = 1;
c = getchar();
}
while(c != EOF && isdigit(c)){
a = (a << 3) + (a << 1) + (c ^ '0');
c = getchar();
}
return f ? -a : a;
} const int MAXN = 20010;
long long dp[1010][41][41] , num[MAXN][3];
int ch[MAXN][2] , headSt , N; void dfs(int now){
++headSt;
if(now < 0){
now = -now;
for(int i = 0 ; i <= 40 ; ++i)
for(int j = 0 ; j <= 40 ; ++j)
dp[headSt][i][j] = (num[now][0] + i) * (num[now][1] + j) * num[now][2];
return;
}
dfs(ch[now][0]);
dfs(ch[now][1]);
for(int i = 0 ; i < 40 ; ++i)
for(int j = 0 ; j < 40 ; ++j)
dp[headSt - 2][i][j] = min(dp[headSt - 1][i + 1][j] + dp[headSt][i][j] , dp[headSt - 1][i][j] + dp[headSt][i][j + 1]);
headSt -= 2;
} int main(){
N = read();
for(int i = 1 ; i < N ; i++){
ch[i][0] = read();
ch[i][1] = read();
}
for(int i = 1 ; i <= N ; i++){
num[i][0] = read();
num[i][1] = read();
num[i][2] = read();
}
dfs(1);
cout << dp[1][0][0];
return 0;
}

HNOI2018做题笔记的更多相关文章

  1. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

  2. C语言程序设计做题笔记之C语言基础知识(上)

    C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...

  3. SDOI2017 R1做题笔记

    SDOI2017 R1做题笔记 梦想还是要有的,万一哪天就做完了呢? 也就是说现在还没做完. 哈哈哈我竟然做完了-2019.3.29 20:30

  4. SDOI2014 R1做题笔记

    SDOI2014 R1做题笔记 经过很久很久的时间,shzr又做完了SDOI2014一轮的题目. 但是我不想写做题笔记(

  5. SDOI2016 R1做题笔记

    SDOI2016 R1做题笔记 经过很久很久的时间,shzr终于做完了SDOI2016一轮的题目. 其实没想到竟然是2016年的题目先做完,因为14年的六个题很早就做了四个了,但是后两个有点开不动.. ...

  6. LCT做题笔记

    最近几天打算认真复习LCT,毕竟以前只会板子.正好也可以学点新的用法,这里就用来写做题笔记吧.这个分类比较混乱,主要看感觉,不一定对: 维护森林的LCT 就是最普通,最一般那种的LCT啦.这类题目往往 ...

  7. java做题笔记

    java做题笔记 1. 初始化过程是这样的: 1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化: 2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序 ...

  8. SAM 做题笔记(各种技巧,持续更新,SA)

    SAM 感性瞎扯. 这里是 SAM 做题笔记. 本来是在一篇随笔里面,然后 Latex 太多加载不过来就分成了两篇. 标 * 的是推荐一做的题目. trick 是我总结的技巧. I. P3804 [模 ...

  9. PKUWC/SC 做题笔记

    去年不知道干了些啥,什么省选/营题都没做. 现在赶应该还来得及(?) 「PKUWC2018」Minimax Done 2019.12.04 9:38:55 线段树合并船新玩法??? \(O(n^2)\ ...

随机推荐

  1. App里面如何正确显示用户头像

    1.说明,一般用户头像在上传的时候都会处理为正方形,如果没有处理该怎么正确显示用户头像呢?解决方案:用css强制 在线地址移动端:戳这里 <div class="main-meimg& ...

  2. Java:JDBC的基本使用

    本文内容: 什么是JDBC JDBC的使用 事务 连接池 DbUtils 首发日期:2018-05-27 修改: 2018-07-19:增加了事务.连接池.DBUtils 2018-07-27:对特别 ...

  3. Python中DataFrame去重

    # 去除重复行数据 keep:'first':保留重复行的第一行,'last':保留重复行的最后一行,False:删除所有重复行df = df.drop_duplicates( subset=['YJ ...

  4. 鸟哥的 Linux 私房菜Shell Scripts篇(三)

    参考: http://linux.vbird.org/linux_basic/0340bashshell-scripts.php#script_be http://www.runoob.com/lin ...

  5. JSON数据提取

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写.同时也方便了机器进行解析和生成.JSON在数据交换中起到了一个载体的作用 ...

  6. 通信原理之OSI七层参考模型(一)

    1.什么是计算机网络 谈计算机通信原理当然离不开计算机网络,那么什么是计算机网络.官方定义:计算机网络是由两台或两台以上的计算机通过网络设备连接起来所组成的一个系统,在这个系统中计算机与计算机之间可以 ...

  7. ccf--20150303--节日

    本题思路:首先,计算a月1日是星期几,然后再通过b和c得出日期monday,最后判断monday是否合法. 题目与代码如下: 问题描述 试题编号: 201503-3 试题名称: 节日 时间限制: 1. ...

  8. February 6th, 2018 Week 6th Tuesday

    To be is to be perceived. 存在即被感知. How to interpret this quote? Maybe it means that everything in you ...

  9. Postgresql 截取字符串

    截取字符串一般用 substring 就够用了.对于有些长度不定的就没法用这个函数了,但还是有规律的,可以某个字符分割. 如:(这是一个url,截取最后一部分.现在要取 - 后面部分内容) 8a59e ...

  10. socket 总结

    网络编程之进程:http://www.cnblogs.com/1a2a/p/7428759.html 网络编程之进阶:http://www.cnblogs.com/1a2a/p/7444446.htm ...