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. java内省机制Introspector

    访问JavaBean属性的两种方式 1)直接调用bean的setXXX或getXXX方法: 2)通过内省技术访问(java.beans包提供了内省的API),内省技术访问也提供了两种方式: a)通过P ...

  2. 你不知道的JSON的高效率用法

    1.JSON JSON是JavaScript Object Notation的缩写,是JavaScript标准的一个子集.官方Android API已经内置支持读写JSON数据.这种格式非常适合表示不 ...

  3. 认识k_BackingField【转】

    事情从Json的序列化和反序列化说起. 在C#2.0的项目中,以前经常使用Json.Net实现序列化和反序列化.后来从c#3.0中开始使用新增的DataContractJsonSerializer进行 ...

  4. CentOS7配置Nodejs环境安装记录

    今天购买了阿里云服务器,系统选的是CentOS7,下面记录下在它上面安装Nodejs环境的过程,本次操作是直接连接的阿里云服务器的管理终端. 1.由于是纯净的环境,先通过以下命令安装nodejs编译及 ...

  5. OpenJ_Bailian 2814 拨钟问题

    总时间限制:  1000ms 内存限制:  65536kB 描述 有9个时钟,排成一个3*3的矩阵. |-------| |-------| |-------|| | | | | | ||---O | ...

  6. 五、IO编程

    input/output:输入.输出 Stream(流):Input Stream就是数据从外面(磁盘.网络)流进内存,Output Stream就是数据从内存流到外面去.(流:相当于管道) 由于CP ...

  7. Win10系列:VC++ Direct3D模板介绍3

    (4)Render函数 默认定义在CubeRenderer.cpp源文件中的Render函数用于绘制立体图形,此函数的实现代码如下所示: void CubeRenderer::Render() {   ...

  8. 洛谷P1600 天天爱跑步(线段树合并)

    小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn ...

  9. Simple上网导航--静态版

    现在的网址导航显然是一个针对小白用户的网页大全,新闻.笑话.视频.黄段子要什么有什么,一个网址导航竟然也要滑动好多页.其实80%的功能我都用不到,但是它们却时刻展现在我的眼前.所以我决定做一个简洁清晰 ...

  10. C的动态链表建立

    运用到的函数为: 动态内存分配函数malloc()              比如:char *name=(char *)malloc(20);  相当与c++的new关键字 动态内存释放函数free ...