2017-5-14 省賽模板

  • 簡介
  • 搜索
    • 迷宮(BFS+隊列)
  • 最短路
    • Dijkstra+鄰接矩陣
    • Dijkstra+鏈式前向星+優(yōu)先隊列
    • Bellman-Ford + 鏈式前向星
    • Bellman-Ford(標準)
    • Floyd
    • SPFA+鄰接矩陣
    • SPFA+DFS
    • 最短路例題
  • 生成樹
    • Kruskal
    • Prim
    • 次小生成樹例題
  • 并查集
    • 一般并查集
    • 帶權(quán)并查集
    • 并查集例題
  • 線段樹
    • 漂浮法
    • 線段樹例題
  • 動態(tài)規(guī)劃
    • 最長公共子序列
    • 最長非降子序列(樸素)
    • 最長非降子序列(二分)
    • 最大字段和
    • 遞推例題
    • 01背包
    • 初始化的細節(jié)問題
    • 完全背包問題
    • 多重背包問題
    • 數(shù)位DP例題
    • 狀壓DP
    • 樹形DP
  • 數(shù)學
    • GCD與LCM
    • 簡易擴展歐幾里得算法
  • 雜項模板
    • 萬金油小算法
    • STL用法
    • 其他

簡介

自用模板。

盡量選用題目來對模板進行解釋拘泞。

搜索

迷宮(BFS+隊列)

用結(jié)構(gòu)體作為隊列元素纷纫,三維數(shù)組存儲地圖。找到起點陪腌,入隊涛酗,遍歷前后左右上下移動,分別入隊偷厦。用vis數(shù)組進行判重商叹。

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;

struct node{
int x, y, z;
int step;
};
int sx, sy, sz; // 儲存起始點坐標
int to[6][3]{1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1}; // 移動方向
int L, R, C; // 長寬高
char map[30][30][30];
int cnt, vis[30][30][30];

int check(int x, int y, int z){ // check it is illegal or not
if(x<0 || x>=L || y<0 || y>=R || z<0 || z>=C) return 1;
if(vis[x][y][z] || map[x][y][z] == '#') return 1;
return 0;
}

void bfs(){
queue<node> q;
node a, b;
a.x = sx, a.y = sy, a.z = sz;
a.step = 0;
vis[a.x][a.y][a.z] = 1;
q.push(a);
while(!q.empty()){
a = q.front(); q.pop();
if(map[a.x][a.y][a.z] == 'E'){ // 遇到終點結(jié)束
cnt = a.step;
return;
}
for(int i=0; i<6; i++){ // 前后左右上下移動
b = a;
b.x += to[i][0];
b.y += to[i][1];
b.z += to[i][2];
if(check(b.x, b.y, b.z)) continue;
b.step = a.step + 1;
vis[b.x][b.y][b.z] = 1;
q.push(b);
}
}
cnt = -1;
}

int main(){
while(scanf("%d%d%d", &L, &R, &C), L){
for(int i=0; i<L; i++)
for(int j=0; j<R; j++)
scanf("%s", map[i][j]); // input
for(int i=0; i<L; i++)
for(int j=0; j<R; j++)
for(int k=0; k<C; k++)
if(map[i][j][k] == 'S'){
sx = i; sy = j; sz = k; // find start
}
memset(vis, 0, sizeof(vis)); // initial
bfs();
if(cnt == -1) { printf("Trapped!\n"); } // output
else printf("Escaped in %d minute(s).\n", cnt);
}
return 0;
}

最短路

Dijkstra+鄰接矩陣

鄰接矩陣設(shè)置為全局變量,無向邊存儲兩次只泼。結(jié)果是起點到所有點的最短距離數(shù)組剖笙,不能判負環(huán)。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1000;

int map[maxn][maxn];
int pre[maxn], dis[maxn];
bool vis[maxn];
int n,m;

void Dijkstra(int s){
memset(dis,0x3f,sizeof(dis));
memset(pre,-1,sizeof(pre));
memset(vis,false,sizeof(vis));
for(int i=1;i<=n;++i){
dis[i]=map[s][i];
pre[i]=s;
}
dis[s]=0;
vis[s]=true;
for(int i=2;i<=n;++i){
int mindist=INF;
int u=s;
for(int j=1;j<=n;++j)
if((!vis[j])&&dis[j]<mindist){
u=j; mindist=dis[j];
}
vis[u] = true;
for(int j=1;j<=n;++j)
if((!vis[j]) && map[u][j] < INF){
if(map[u][j] + dis[u] < dis[j]){
dis[j] = map[u][j] + dis[u];
pre[j] = u;
}
}
}
}

Dijkstra+鏈式前向星+優(yōu)先隊列

該模板需要初始化请唱。
通過addnode方法加邊弥咪,無向邊讀取兩遍。優(yōu)先隊列優(yōu)化時間效率十绑,鏈式前向星遍歷某節(jié)點下所有邊聚至,同時優(yōu)化空間效率。結(jié)果是一個從起點到所有點的最短距離數(shù)組本橙。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1000;

struct node{
int d,u;
friend bool operator<(node a,node b){
return a.d>b.d;
}
node(int dist,int point):d(dist),u(point){}
};

struct Edge{
int to,next;
int dist;
}edge[maxm];
int head[maxn],tot;
int pre[maxn],dis[maxn];

void init(){
memset(head,-1,sizeof(head));
tot=0;
}

void addedge(int u,int v,int d){
edge[tot].to=v;
edge[tot].dist=d;
edge[tot].next=head[u];
head[u]=tot++;
}

void Dijkstra(int s){
priority_queue<node> q;
memset(dis,0x3f,sizeof(dis));
memset(pre,-1,sizeof(pre));
dis[s]=0;
while(!q.empty()) q.pop();
node a(0,s); q.push(a);       //起點入隊列
while(!q.empty()){
node x=q.top(); q.pop();
if(dis[x.u]<x.d) continue;
for(int i=head[x.u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(dis[v]>dis[x.u]+edge[i].dist){
dis[v]=dis[x.u]+edge[i].dist;
pre[v]=x.u;
q.push(node(dis[v],v));
}
}
}
}

Bellman-Ford + 鏈式前向星

我個人感覺這個算法的優(yōu)化在于重邊扳躬,以及松弛函數(shù)與主算法的分離。某些只針對松弛的題目變化可以很方便地使用甚亭。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
struct Edge{
int u, v;
double r, c;
}edge[maxn*2];

double mostMoney[maxn];
int n, m, s;
double v;
int tot;

void addedge(int u, int v, double r, double c){
edge[tot].u = u;
edge[tot].v = v;
edge[tot].r = r;
edge[tot++].c = c;
}

bool relax(int n){
double temp = (mostMoney[edge[n].u] - edge[n].c)*edge[n].r;
if (temp > mostMoney[edge[n].v]){
mostMoney[edge[n].v] = temp;
return true;
}
return false;
}

bool bellman_ford(){
bool flag;
for (int i=0; i<n; i++) mostMoney[i] = 0.0;
mostMoney[s] = v;
for (int i=0; i<n-1; ++i){
flag = false;
for (int j=0; j<tot; ++j)
if (relax(j)) flag = true;
if (mostMoney[s] > v) return true;
if (!flag) return false;
}
for (int i=0; i<tot; ++i)
if (relax(i)) return true;
return false;
}

Bellman-Ford(標準)

用簡單的結(jié)構(gòu)體來存儲數(shù)據(jù)贷币、遍歷。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1000;

struct Edge{
int u,v; //起點亏狰、終點
int dist; //長度
}edge[maxn];

int dis[maxn]; //最短距離數(shù)組
int n, m; //結(jié)點數(shù)役纹、邊數(shù)

bool Bellman_ford(int s){
memset(dis, INF, sizeof(dis));
dis[s]=0;
for(int k=1; k<n; ++k){ //迭代n-1次
for(int i=0; i<m; ++i){  //檢查每條邊
int x = edge[i].u, y = edge[i].v;
if(dis[x] < INF)
dis[y] = min(dis[y], dis[x] + edge[i].dist);
}
}
bool flag=1;
for(int i=0; i<m; ++i){   //判斷是否有負環(huán)
int x = edge[i].u, y = edge[i].v;
if(d[y] > d[x] + edge[i].dist){
flag = 0; break;
}
}
return flag;
}

Floyd

此算法三重循環(huán)是有順序的。

最短路松弛算法為:
map[i][j] = min(map[i][k]+map[k][j], map[i][j])

最外層循環(huán)為中繼點暇唾,第二次為起點促脉,第三層為終點辰斋。

void floyd(){
for(int k=1; k<=n; ++k)
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
if (map[i][j] > map[i][k] + map[k][j]) //松弛
map[i][j] = map[i][k] + map[k][j];
}

SPFA+鄰接矩陣

void spfa(int s){
for(int i=0; i<=n; i++) dis[i]=0x3f3f3f3f; //初始化每點到s的距離
dis[s]=0; vis[s]=1; q[1]=s;  //隊列初始化,s為起點
int i, v, head=0, tail=1;
while (head++<tail){   //隊列非空
v=q[head];  //取隊首元素
vis[v]=0;   //釋放隊首結(jié)點,因為這節(jié)點可能下次用來松弛其它節(jié)點瘸味,重新入隊
for(i=0; i<=n; i++)  //對所有頂點
if (a[v][i]>0 && dis[i]>dis[v]+a[v][i]){
dis[i] = dis[v]+a[v][i];   //修改最短路
if (vis[i]==0){  //如果擴展結(jié)點i不在隊列中宫仗,入隊
q[++tail]=i;
vis[i]=1;
}
}
}
}

SPFA+DFS

a[i][j]存儲從ij所需要的距離。

b[i][j]=w存儲從iwi結(jié)點下的第j條邊硫戈。

void spfa(int s){
for(int i=1; i<=b[s][0]; i++)  //b[s,0]是從頂點s發(fā)出的邊的條數(shù)
if (dis[b[s][i]]>dis[s]+a[s][b[s][i]]){  //b[s,i]是從s發(fā)出的第i條邊的另一個頂點
dis[b[s][i]=dis[s]+a[s][b[s][i]];
spfa(b[s][i]);
}
}

最短路例題

CSU - 1808

題意

最短路锰什。

給出n個地鐵站下硕,m條邊丁逝,給出每條邊的首尾地鐵站a、b梭姓,和這條邊所屬的地鐵線c霜幼,以及這條邊的邊權(quán)d

地鐵線之間需要換乘誉尖,換乘時間為abs(ci-cj)罪既。
因為多了一個換乘時間,所以需要拆點铡恕。

用鏈式前向星存邊琢感,用map<int,int>拆點,用vector存當前點所在的地鐵探熔。

思路

首先讀邊驹针。用map[u][x]來表示u地鐵站在x號線上,存儲一個標記值cnt诀艰,代表這個點是第幾個點(重新編號)柬甥。然后取出這個點。v點同樣其垄。最后addedge兩遍苛蒲。

遍歷所有點。對每個點下的vector排個序绿满,這樣就可以避免取絕對值臂外。對每個點遍歷vector,對于vector中的每條地鐵線喇颁,將這個點取出添邊寄月。

制圖之后就按照模板跑Dijkstra,注意最后獲取結(jié)果的時候要跑一遍n點的vector找最小值无牵。

代碼

/******************************
*File name: csu1808.cpp
*Author: wzhzzmzzy
*Created Time: 一  4/17 20:54:29 2017
*TODO: CSU 1808 最短路
******************************/

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
using namespace std;
const int maxn = 300005;
const int inf = 0x3f3f3f3f;

int n, m;
struct Edge{
int to, next;
int w;
}edge[maxn<<1];

int head[maxn], tot;

void init(){
memset(head, -1, sizeof(head));
tot = 0;
}

void addedge(int u, int v, int w){
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}

vector<int> num[maxn];
//某站所屬的線路
map<int,int> mmp[maxn];
//某站是記錄的第幾個地鐵站(拆點)
int dis[maxn], cnt;

struct node{
int now, c;
node(int _n=0, int _c=0):now(_n), c(_c){}
friend bool operator <(node a, node r){
return a.c > r.c;
}
};

void Dijkstra(){
priority_queue<node> q;
while (!q.empty()) q.pop();
for (int i = 1; i < cnt; ++i) dis[i] = inf;
for (int i = 0; i < num[1].size(); ++i){
int st = mmp[1][num[1][i]];
dis[st] = 0;
q.push(node(st, 0));
}
node temp;
while (!q.empty()){
temp = q.top(); q.pop();
int u = temp.now;
int cost = temp.c;
if (cost > dis[u]) continue;
for (int i = head[u]; ~i; i=edge[i].next){
int v = edge[i].to;
int w = edge[i].w;
if (dis[v] > cost+w){
dis[v] = cost + w;
q.push(node(v, dis[v]));
}
}
}
}

int main(){
int u, v, x, w;
while (~scanf("%d%d", &n, &m)){
init();
cnt = 1;
for (int i = 1; i <= n; ++i){
num[i].clear();
mmp[i].clear();
}
for (int i = 0; i < m; ++i){
scanf("%d%d%d%d", &u, &v, &x, &w);
if (!mmp[u][x]){
mmp[u][x] = cnt++;
num[u].push_back(x);
}
u = mmp[u][x];
if (!mmp[v][x]){
mmp[v][x] = cnt++;
num[v].push_back(x);
}
v = mmp[v][x];
addedge(u, v, w);
addedge(v, u, w);
}
for(int i = 1; i <= n; ++i){
sort(num[i].begin(), num[i].end());
for(int j = 0; j < num[i].size()-1; ++j){
u = mmp[i][num[i][j]];
v = mmp[i][num[i][j+1]];
w = num[i][j+1] - num[i][j]; //同一站點不同線路的拆點之間的差值
addedge(u, v, w);
addedge(v, u, w);
}
}
Dijkstra();
int ans = inf;
for (int i = 0; i < num[n].size(); ++i){
u = mmp[n][num[n][i]];
ans = min(ans, dis[u]);
}
printf("%d\n", ans);
}
return 0;
}

生成樹

Kruskal

用并查集來將所有的節(jié)

點組織成一棵樹漾肮。不需要正反讀無向邊,默認無向茎毁。

#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn;
int fa[maxn];
int n, m;

struct Edge{
int u, v, w;
}edge[maxn];

bool cmp(Edge a,Edge b){
return a.w < b.w;
}

int find(int x){
return fa[x] == x? x: fa[x] = find(fa[x]);
}

int Kruskal(){
int ans = 0;
for(int i=0; i<=n; ++i)
fa[i]=i;
sort(edge, edge+m, cmp);
for(int i = 0; i < m; ++i){
int x = find(edge[i].u);
int y = find(edge[i].v);
if(x != y){
ans += edge[i].w;
fa[x] = y;
}
}
return ans;
}

Prim

void prim(){
int mi, v = 0;
for(int i = 0; i < n; i++){
dis[i] = map[0][i];
vis[i] = false;
}

for(int i = 1; i <= n; i++){
mi = INF;
for(int j = 0; j < n; j++)
if(!vis[j] && mi > dis[j]){
v = j;
mi = dis[j];
}
vis[v] = true;
for(int j = 0; j < n; j++)
if(!vis[j] && dis[j] > map[v][j])
dis[j] = map[v][j];
}
for(int i = 1; i < n; i++)
dis[0] += dis[i]; //統(tǒng)計生成樹長度
}

次小生成樹例題

POJ-1679

題意

套用kuangbin的次小生成樹模板克懊。

只要找到次小生成樹忱辅,然后和最小生成樹比較一下即可。

代碼

/******************************
*File name: poj1679.cpp
*Author: wzhzzmzzy
*Created Time: 五  4/21 17:18:59 2017
*TODO: POJ 1679 次小生成樹
******************************/

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 105;

bool vis[maxn], used[maxn][maxn];
int lowc[maxn], pre[maxn], Max[maxn][maxn];

int prim(int cost[][maxn], int n){
int ans = 0;
memset(Max, 0, sizeof Max);
memset(used, false, sizeof used);
memset(vis, false, sizeof vis);
vis[0] = true;
pre[0] = -1;
for (int i = 1; i < n; ++i){
lowc[i] = cost[0][i];
pre[i] = 0;
}
lowc[0] = 0;
for (int i = 1; i < n; ++i){
int minc = inf;
int p = -1;
for (int j = 0; j < n; ++j) if (!vis[j] && minc > lowc[j]){
minc = lowc[j];
p = j;
}
if (minc == inf) return -1;
ans += minc;
vis[p] = true;
used[p][pre[p]] = used[pre[p]][p] = true;
for (int j = 0; j < n; ++j){
if (vis[j]) Max[j][p] = Max[p][j] = max(Max[j][pre[p]], lowc[p]);
if (!vis[j] && lowc[j] > cost[p][j]){
lowc[j] = cost[p][j];
pre[j] = p;
}
}
}
return ans;
}

int ans;
int check(int cost[][maxn], int n){
int Min = inf;
for (int i = 0; i < n; ++i)
for (int j = i + 1; j < n; ++j)
if (cost[i][j] != inf && !used[i][j])
Min = min(Min, ans + cost[i][j] - Max[i][j]);
if (Min == inf) return -1;
return Min;
}

void solve(){
int cost[maxn][maxn], n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j){
if (i == j) cost[i][j] = 0;
else cost[i][j] = inf;
}
while (m--){
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
--x, --y;
cost[x][y] = cost[y][x] = w;
}
ans = prim(cost, n);
if (ans == -1 || ans == check(cost, n)) printf("Not Unique!\n");
else printf("%d\n", ans);
}

int main(){
int t;
scanf("%d", &t);
while (t--) solve();
return 0;
}

并查集

一般并查集

int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void join(int x, int y) {
int fx = find(x), fy = find(y);
if (fx != fy) fa[fx] = fy;
}

帶權(quán)并查集

而帶權(quán)并查集谭溉,其中的權(quán)需要轉(zhuǎn)化成子節(jié)點與父節(jié)點之間的聯(lián)系墙懂。這樣向上查找時就能發(fā)現(xiàn)父節(jié)點和子節(jié)點之間的關(guān)系,以此來進行計算扮念。

帶權(quán)并查集的壓縮路徑方法是损搬,在遞歸向上查找的同時,因為遞歸是直接到達最深處然后向上回溯的柜与,所以只需要對每個點都做一次累加巧勤,這樣回到原來的位置時就是全部的累加。合并樹操作各有不同弄匕,主要是創(chuàng)建父節(jié)點的操作颅悉。

舉個例子,蟲子的一生( POJ - 2492 )中用權(quán)數(shù)組表示兩個蟲子的性別關(guān)系迁匠,更新時就只要考慮一下同性還是異性即可剩瓶。

并查集例題

POJ - 1733

題解

并查集+離散化。
有一個01串城丧,1e9位延曙。給出一些子串,和他們中有奇數(shù)個還是偶數(shù)個1,求這些中有幾個是對的。
因為長度太長所以開不下這么多數(shù)組疹蛉,而子串只有五千個,所以需要哈希一下魂仍。只要存最多一萬個數(shù)字就可以。為了避免不在一起的相鄰所以多存一位拣挪,就是兩萬位擦酌。然后用一個數(shù)組存當前下標之前有奇數(shù)還是偶數(shù)個1,最后用并查集求解菠劝。

代碼

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100005;

int fa[maxn], val[maxn], n, m;
int hashSet[maxn];

struct {
int u, v, w;
}node[maxn];

int find(int n){
int k = fa[n];
if(fa[n] != n){
fa[n] = find(fa[n]);
val[n] = (val[n] + val[k])%2;
}
return fa[n];
}

void init(){
for (int i = 0; i <= n; ++i)
val[i] = 0, fa[i] = i;
}

int main(){
while (~scanf("%d", &n)){
int i, k = 0;

//init放在這里會RE

scanf("%d", &m);
for (i = 0; i < m; ++i){
char s[5];
scanf("%d%d%s", &node[i].u, &node[i].v, s);
node[i].w = s[0] == 'e'? 0:1;

hashSet[k++] = node[i].u - 1;
hashSet[k++] = node[i].u;
hashSet[k++] = node[i].v - 1;
hashSet[k++] = node[i].v;
}
hashSet[k++] = n;
hashSet[k++] = n - 1;

sort(hashSet, hashSet+k);
n = (int)(unique(hashSet, hashSet+k) - hashSet);

init();
//init放這里就AC

for (i = 0; i < m; ++i){
int u = (int)(lower_bound(hashSet, hashSet+n, node[i].u-1) - hashSet);
int v = (int)(lower_bound(hashSet, hashSet+n, node[i].v) - hashSet);

int fu = find(u), fv = find(v);

if (fu == fv && (val[u] + node[i].w)%2 != val[v])
break;
if (fu < fv){
fa[fv] = fu;
val[fv] = (val[u] + node[i].w - val[v] + 2) % 2;
}
if (fu > fv){
fa[fu] = fv;
val[fu] = (val[v] - node[i].w - val[u] + 2) % 2;
}
}
printf("%d\n", i);
}
return 0;
}

線段樹

漂浮法

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <queue>
#include <string>
using namespace std;

int t, n, a, b;
#define maxn  10001
int l[maxn], l[maxn];
int ans[maxn];

void cover(int a, int b, int to, int id) {
while (to <= n && (b < l[to] || a > r[to]))
to++;
if (to == n+1) {
ans[id] = b - a + 1; return;
}
if (a < l[to])
cover(a, l[to] - 1, to + 1, id);
if (b > r[to])
cover(r[to] + 1, b, to + 1, id);
}

int main() {
scanf("%d", &t);
while (t--) {
memset(ans, 0, sizeof(ans));
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d %d", &l[i], &r[i]);
for (int i = n; i >= 1; i--)
cover(l[i], r[i], i + 1, i);
int cnt = 0;
for (int i = 1; i <= n; i++)
if (ans[i])cnt++;
printf("%d\n", cnt);
}
}

線段樹例題

POJ-3468

代碼

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <queue>
#include <string>
using namespace std;

#define maxn 100010<<2
#define maxm 1000000000

int n, m;
long long A[100010];
long long Sum[maxn];
long long Add[maxn];

void pushup(int rt) {
Sum[rt] = Sum[rt << 1] + Sum[rt << 1 | 1];
}
void build(int l,int r,int rt) {
if (l == r) { Sum[rt] = A[l]; return; }
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
void pushdown(int rt,int ln,int rn) {
if (Add[rt]) {
Add[rt << 1] += Add[rt];
Add[rt << 1 | 1] += Add[rt];
Sum[rt << 1] += Add[rt] * ln;
Sum[rt << 1 | 1] += Add[rt] * rn;
Add[rt] = 0;
}
}
void update(int a, int b, int c, int l, int r, int rt) {
if (a <= l&&b >= r) {
Sum[rt] += c*(r - l + 1);
Add[rt] += c;//本區(qū)間正確赊舶,子區(qū)間Sum仍然要用Add增加
return;
}
int m = (l + r) >> 1;
pushdown(rt, m - l + 1, r - m);
if (a <= m)update(a, b, c, l, m, rt << 1);
if (b > m)update(a, b, c, m + 1, r, rt << 1 | 1);
pushup(rt);
}
long long query(int a, int b, int l, int r, int rt) {
if (a <= l&&b >= r) { return Sum[rt]; }
int m = (l + r) >> 1;
pushdown(rt, m - l + 1, r - m);
long long ans = 0;
if (a <= m)ans += query(a, b, l, m, rt << 1);
if (b > m)ans += query(a, b, m + 1, r, rt << 1 | 1);
return ans;
}
int main() {
while (~scanf("%d %d", &n, &m)) {
memset(Add, 0, sizeof(Add));
for (int i = 1; i <= n; i++) {
scanf("%lld", &A[i]);
}
build(1, n, 1);
char s[10];
int a, b, c;
for (int i = 1; i <= m; i++) {
scanf("%s", s);
if (s[0] == 'Q') {
scanf("%d %d", &a, &b);
printf("%lld\n",query(a, b, 1, n, 1));
}
else {
scanf("%d %d %d", &a, &b, &c);
update(a, b, c, 1, n, 1);
}
}
}
}

動態(tài)規(guī)劃

最長公共子序列

if (a[i] == b[j])
dp[i][j] = dp[i-1][j-1]+1;
else
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);

最長非降子序列(樸素)

dp[i]存儲a[i]位置及之前最長非降子序列長度。

for (int i = 1; i <= n; ++i)
for (int j = 1; j < i; ++j)
if (a[i] >= a[j])
dp[i] = max(dp[i], dp[j]+1);

最長非降子序列(二分)

for (int i = 1; i <= n; ++i){
int k = upper_bound(a[i]);
b[k+1] = a[i];
}

最大字段和

int f(int n){
bool flag = false;
for (int i = 1; i <= n; ++i){
if (!flag && a[i] > 0) flag = true;
if (dp[i-1] + a[i] < 0) dp[i] = 0;
else dp[i] = dp[i-1] + a[i];
}
if (!flag){
int ans = 0;
for (int i = 1; i <= n; ++i)
ans += a[i];
return ans;
}
else return dp[n];
}

遞推例題

POJ - 1661

題意

Jimmy從坐標為(x,y)的點掉落下來赶诊,速度1單位/s笼平,如果掉落下去的距離超過了max就會摔死√蚧荆空間中有許多橫著的木板寓调,屬性為(x1,x2,h)。在木板上可以橫向移動锄码,速度1單位/s夺英。求最快到達地面的時間晌涕。

題解

基礎(chǔ)DP。

dp[i][0]表示從第i塊木板左側(cè)掉落的到達地面時間痛悯,dp[i][1]表示右側(cè)余黎。轉(zhuǎn)移方程為:

dp[i][0] =
p[i].h - p[k].h +
min(dp[k][0]+p[i].x1-p[k].x1,
dp[k][1]+p[k].x2-p[i].x1);
dp[i][1] =
p[i].h - p[k].h +
min(dp[k][0]+p[i].x2-p[k].x1,
dp[k][1]+p[k].x2-p[i].x2);

代碼

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;

struct plat{
int x1, x2, h;
}p[1005];
int maxn, dp[1005][2];

bool cmp(plat a, plat b){
return a.h < b.h;
}

void calc_left(int i){
int k = i - 1;
while (k > 0 && p[i].h - p[k].h <= maxn){
if (p[i].x1 >= p[k].x1 && p[i].x1 <= p[k].x2){
dp[i][0] = p[i].h - p[k].h + min(dp[k][0]+p[i].x1-p[k].x1,
dp[k][1]+p[k].x2-p[i].x1);
return;
} else --k;
}
if (p[i].h - p[k].h > maxn)
dp[i][0] = 0x3f3f3f3f;
else
dp[i][0] = p[i].h;
}

void calc_right(int i){
int k = i - 1;
while (k > 0 && p[i].h - p[k].h <= maxn){
if (p[i].x2 >= p[k].x1 && p[i].x2 <= p[k].x2){
dp[i][1] = p[i].h - p[k].h + min(dp[k][0]+p[i].x2-p[k].x1,
dp[k][1]+p[k].x2-p[i].x2);
return;
} else --k;
}
if (p[i].h - p[k].h > maxn)
dp[i][1] = 0x3f3f3f3f;
else
dp[i][1] = p[i].h;
}

void solve(){
memset(dp, 0, sizeof dp);
int n;
scanf("%d%d%d%d", &n, &p[0].x1, &p[0].h, &maxn);
++n, p[0].x2 = p[0].x1;
for (int i = 1; i < n; ++i)
scanf("%d%d%d", &p[i].x1, &p[i].x2, &p[i].h);
p[n].x1 = -20001, p[n].x2 = 20001, p[n].h = 0;
sort(p, p+n+1, cmp);

for (int i = 1; i <= n; ++i){
calc_left(i);
calc_right(i);
}

printf("%d\n", min(dp[n][0], dp[n][1]));
}

int main(){
int t;
scanf("%d", &t);
while (t--) solve();
return 0;
}

01背包

每個物品只能放入一次。

思路

f[i][v]表示载萌,第i個大小為v的物品放入時的總價值惧财。

c[i]表示第i個物品的價值。w[i]為第i個物品的大小扭仁。

狀態(tài)轉(zhuǎn)移方程:f[i][v] = max(f[i-1][v], f[i-1][v-w[i]]+c[i]);

狀態(tài)轉(zhuǎn)移方程表示垮衷,取放入或者不放入第i個物品兩種情況的最大值。

空間優(yōu)化(滾動數(shù)組)

初始狀態(tài)方程的空間復(fù)雜度是O(V*W)斋枢,可以進一步優(yōu)化帘靡。

可以將空間優(yōu)化為O(2*W)知给,即縱向大小為2瓤帚。

for(i=1; i<=N; i++){
for(j=t[i]; j<=V; j++)
f[t^1][j] = max(f[c][j-w[i]]+c[i], f[t][j]);
t ^= 1;
}

異或滾動可以在0和1之間切換,可以利用上下反復(fù)更新涩赢。

空間優(yōu)化(一維數(shù)組)

既然可以用兩行進行更新戈次,那為什么不能用一行。

觀察問題筒扒,兩行更新時怯邪,用上一行的前部分更新下一行的后部分。

所以單行更新時要從后往前遍歷花墩,這樣可以用前面的更新后面的悬秉。

for(i=1; i<=N; i++)
for(j=V; j>=w[i]; j--)
f[j] = max(f[j-w[i]]+c[i], f[j]);

這樣就可以用一維數(shù)組來進行更新。

可以寫成函數(shù)冰蘑,封裝起來和泌。

void ZeroOnePack(int cost, int weight){
for(int i=V; i>=weight; i++)
f[i] = max(f[i], f[i-weight]+cost)
}

初始化的細節(jié)問題

一般問題會有兩種問法:

  1. 剛好裝滿背包
  2. 不用裝滿背包

如果是第一種,f[0]=0,f[1]……f[N]=INF;

如果是第二種祠肥,f[0]……f[N]=INF;

理解:

如果是第一種武氓,初始狀態(tài)只有0符合理想狀態(tài),只有0才能被空“裝滿”仇箱。

如果是第二種县恕,所有都符合理想狀態(tài)。

完全背包問題

和01背包相似剂桥,所不同的是可取的物品數(shù)是無限忠烛。

前置小優(yōu)化

對于i``j兩個物品,如果c[i]>c[j] && w[i]<w[j]权逗,就舍去i物品美尸。

另外垒拢,針對背包問題而言,比較不錯的一種方法是:首先將重量大于V的物品去掉火惊,然后使用類似計數(shù)排序的做法求类,計算出費用相同的物品中價值最高的是哪個,可以O(shè)(V+N)地完成這個優(yōu)化屹耐。

基本思路

狀態(tài)轉(zhuǎn)移方程f[i][v]=max{f[i-1][v-k*w[i]]+k*c[i]},(0<=k*w[i]<=V)

轉(zhuǎn)化為01背包求解

一件物品最多只能放V/c[i]件尸疆,所以可以把一件物品,看成V/c[i]件物品惶岭,作為01背包解答寿弱。

另一種更好的辦法是把第i種物品拆成大小為w[i]*2^k、價值為c[i]*2^k的若干件物品按灶,其中k滿足w[i]*2^k<=V症革。這是二進制的思想,因為不管最優(yōu)策略選幾件第i種物品鸯旁,總可以表示成若干個2^k件物品的和噪矛。這樣把每種物品拆成O(log(V/w[i]))件物品,是一個很大的改進铺罢。

O(VN)算法

for(int i=1; i<=N; i++)
for(int j=w[i]; j<=V; j++)
f[j] = max{f[v], f[v-w[i]]+c[i]};

這個算法和之前的01背包相比只是第二層的遍歷方向改變了艇挨。因為01背包要保證每個物品只能選擇一次,但是完全背包不必韭赘,所以改變遍歷方向就可以得到結(jié)果缩滨。

這個算法也可以從另外的思路中得出,
例如泉瞻,基本思路中的公式可以化作這個形式:
f[i][v]=max(f[i-1][v], f[i][v-w[i]]+c[i]);

用函數(shù)封裝:

void CompletePack(int cost, int weight){
for(int i=weight; i<=V; i++)
f[i] = max(f[i], f[i-weight]+cost);
}

多重背包問題

每件物品數(shù)量不一定為1但有限脉漏。

基本思路

問題和完全背包很相似。
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[I]}(0<=k<=n[I])
復(fù)雜度為O(V*Σn[i])袖牙。

轉(zhuǎn)化為01背包問題

n[i]存儲侧巨,可以將每種物品轉(zhuǎn)化為n[i]件物品,然后用01背包方案求解贼陶。復(fù)雜度不變刃泡。

如果要進行優(yōu)化的話,依然用二進制思想碉怔,同上烘贴。

這樣可以將時間優(yōu)化為O(V*Σlog n[i])

void MultiplePack(int weight, int cost, int amount){
if(cost * amount >= V){
CompletePack(cost, weight);
return;
}
int k = 1;
while(k < num){// num 為物品種數(shù)
ZeroOnePack(k*cost, k*weight);
amount = amount-k;
k *= 2;
}
ZeroOnePack(amount*cost, amount*weight);
}

數(shù)位DP例題

HDU - 2089

題意

求從lr的所有數(shù)字中撮胧,不含有462的數(shù)字有多少桨踪。

題解

數(shù)位DP入門。

dp[i][j]表示j開頭的i位數(shù)芹啥。首先打表锻离,然后根據(jù)讀入的數(shù)字挨個匹配累加即可铺峭。

遞推公式:

for (int i = 1; i < 7; ++i)
for (int j = 0; j < 10; ++j)
for (int k = 0; k < 10; ++k)
if (j != 4 && !(j == 6 && k == 2))
dp[i][j] += dp[i-1][k];

代碼

/******************************
*File name: hdu2089.cpp
*Author: wzhzzmzzy
*Created Time: 二  4/25 20:05:44 2017
*TODO: HDU 2089 數(shù)位DP
******************************/

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

int dp[8][10];
void init(){
memset(dp, 0, sizeof dp);
dp[0][0] = 1;
for (int i = 1; i < 7; ++i)
for (int j = 0; j < 10; ++j)
for (int k = 0; k < 10; ++k)
if (j != 4 && !(j == 6 && k == 2))
dp[i][j] += dp[i-1][k];
}

int calc(int x){
int digit[8], len = 0, ans = 0;
while (x > 0){
digit[++len] = x%10;
x /= 10;
}
digit[len+1] = 0;
for (int i = len; i; --i){
for (int j = 0; j < digit[i]; ++j)
if (j != 4 && !(digit[i+1]==6&&j==2))
ans += dp[i][j];
if (digit[i] == 4||(digit[i]==2&&digit[i+1]==6))
break;
}
return ans;
}

int main(){
int n, m;
init();
while (~scanf("%d%d", &n, &m) && n && m){
printf("%d\n", calc(m+1)-calc(n));
}
}

狀壓DP

HDU - 1074

題意

給出n門作業(yè)的名稱、截止時間和所需時間汽纠。當超過截止時間時會扣分卫键。求最小的扣分數(shù)和做作業(yè)的順序。

題解

狀態(tài)壓縮DP虱朵。
看了題解才知道這樣做莉炉。
首先是二進制法遍歷集合全排列,然后遍歷當前排列中包含的上一個做完的作業(yè)碴犬,即遍歷每一種作業(yè)絮宁,找出扣分的最小值作為上一個做完的作業(yè)。記錄這一狀態(tài)服协,并且記錄前驅(qū)(輸出用)绍昂。

代碼

/******************************
*File name: hdu1029.cpp
*Author: wzhzzmzzy
*Created Time: 日  4/23 20:01:35 2017
*TODO: HDU 1029 狀壓DP 水
******************************/

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

char name[16][200];
int t[1<<15], deadline[16], finish[16];
int pre[1<<15], dp[1<<15];

void output(int m){
if (!m) return;
output(m-(1<<pre[m]));
printf("%s\n", name[pre[m]]);
}

int main(){
int T;
scanf("%d", &T);
while (T--){
int n;
scanf("%d", &n);
int maxn = 1<<n;
for (int i = 0; i < n; ++i)
scanf("%s%d%d", name[i], deadline+i, finish+i);
for (int i = 1; i < maxn; ++i){
dp[i] = 0x3f3f3f3f;
for (int j = n-1; j >= 0; --j){
int te = 1<<j;
if (!(i&te)) continue;
int score = t[i-te]-deadline[j]+finish[j];
if (score < 0) score = 0;
if (dp[i] > dp[i-te]+score){
dp[i] = dp[i-te]+score;
t[i] = t[i-te]+finish[j];
pre[i] = j;
}
}
}
printf("%d\n", dp[maxn-1]);
output(maxn-1);
}
return 0;
}

樹形DP

HDU - 4044

代碼

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#define ull unsigned long long
#define ll long long
#define mp map
#define FOR(a,b) for(int i=a;i<=b;i++)
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
using namespace std;

int m;
const int maxm = 210;
const int maxn = 1010;

vector<int>aaa[maxn];

int weaponChoice[maxn];
int cost[maxn][52];
int power[maxn][52];
int dp[maxn][maxm];    //dp[i][j]:i與其子樹消耗j資源的最薄弱鏈最大值

void dfs(int u,int fa){
for(int i=m;i>=0;i--){
for(int j=1;j<=weaponChoice[u];j++){
if(cost[u][j]<=i)dp[u][i]=max(dp[u][i],power[u][j]);
}
}

if(aaa[u].size()==1&&u!=1) return;

int maxson[maxn];        //maxson[i]:u子樹花費資源i時最大值
memset(maxson,0x3f3f3f3f,sizeof(maxson));
for(int e=0;e<aaa[u].size();e++){//枚舉u的子節(jié)點
int v=aaa[u][e];
if(v==fa)continue;
dfs(v,u);                    //計算v樹的最優(yōu)解,dp[v]系
for(int i=m;i>=0;i--){        //枚舉給u子樹分配的資源
int maxx=0;
for(int j=0;j<=i;j++){
maxx=max(maxx,min(maxson[i-j],dp[v][j]));    //其他子樹分i-j偿荷,v樹分j
}
maxson[i]=maxx;
}
}
for(int i=m;i>=0;--i)
for(int k=0;k<=i;++k)
dp[u][i]=max(dp[u][i],dp[u][i-k]+maxson[k]);
}
int main(){
int tcase;
scanf("%d",&tcase);
while(tcase--){
memset(dp,0,sizeof(dp));
int n;
scanf("%d",&n);
for(int i=0;i<=n;i++)aaa[i].clear();
int a,b;
for(int i=1;i<n;i++){
scanf("%d %d",&a,&b);
aaa[a].push_back(b);
aaa[b].push_back(a);
}

scanf("%d",&m);
for(int i=1;i<=n;i++){
scanf("%d",&weaponChoice[i]);
for(int j=1;j<=weaponChoice[i];j++){
scanf("%d %d",&a,&b);
cost[i][j]=a;power[i][j]=b;
}
}
dfs(1,-1);
printf("%d\n",dp[1][m]);
}
}

數(shù)學

GCD與LCM

  • GCD計算方式來自公式gcd(a,b)=gcd(b,a%b)
int gcd(int a, int b){
return b>0? b : a%b;
}
  • LCM計算方式來自性質(zhì)ab=gcd(a,b)*lcm(a,b)
int lcm(int a, int b){
return a * b / std::__gcd(a, b);
}
  • 還有一個性質(zhì)lcm(m*a,m*b)=m*gcd(a,b)

簡易擴展歐幾里得算法

void gcd(int a, int b, int& d, int& x, int& y) {
if (!b) { d = a; x = 1; y = 0; }
else { gcd(b, a%b, d, y, x); y -= x*(a / b); }
}

雜項模板

萬金油小算法

快讀

通過getchar和強制類型轉(zhuǎn)換加快讀取整形數(shù)字的速度窘游。

int Input(){
char c;
for (c = getchar(); c<'0' || c>'9'; c = getchar());
int a = c - '0';
for (c = getchar(); c >= '0' && c <= '9'; c = getchar())
a = a*10 + c - '0';
return a;
}

交換

指針交換變量值。

void swap(int* a, int* b){
int t = *a; *a = *b; *b = t;
}

前驅(qū)路徑輸出

遞歸回溯輸出pre數(shù)組中的路徑遭顶。

void output(int cur, int pre[]){
if (cur == 0) return;
output(pre[cur], pre);
printf("%d\n", cur);
}

矩陣快速冪

#include <cstdio>
#include <algorithm>
#include <string.h>
#include <iostream>
using namespace std;
#define maxn 101    //題目極限尺寸

int n;              //實際矩陣尺寸
struct Matrix {
long long mat[maxn][maxn];
};

Matrix operator * (Matrix a, Matrix b) {
Matrix c;
memset(c.mat, 0, sizeof(c.mat));
int i, j, k;
for (k = 0; k < n; ++k) {
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
c.mat[i][j] += a.mat[i][k] * b.mat[k][j];
c.mat[i][j] %= 10000;
}
}
}
return c;
}

Matrix operator ^ (Matrix a, int k) {
Matrix c;
int i, j;
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
c.mat[i][j] = (i == j);    //初始化為單位矩陣

for (; k; k >>= 1) {
if (k & 1) c = c*a;
a = a*a;
}
return c;
}

int main() {
int t;
while (scanf("%d", &t) && t != -1) {
Matrix fib;
n = 2;
fib.mat[0][0] = fib.mat[0][1] = fib.mat[1][0] = 1;
fib.mat[1][1] = 0;
fib = fib^t;
cout << fib.mat[0][1]%10000 << endl;
}
}

STL用法

struct 重載運算符张峰、構(gòu)造函數(shù)

struct node{
int d,u;
friend bool operator<(node a, node b){
return a.d > b.d;
}
node():{}
node(int dist, int point): d(dist), u(point){}
};

std::sort()

按照a字段降序排序泪蔫,a相同時按b降序棒旗。

bool cmp(node a, node b){
if (a.a == b.a)
return a.b > b.b;
else
return a.a > b.a;
}

std::map

map<string,int> a;
a["hello"] = 1;
a["world"] = 2;
for (map<string,int>::iterator i = a.begin(); i != a.end(); ++i)
cout << i->first << " " << i->second << endl;
a.count("world") == 2; // Ture;

auto 變量

C++11,auto為一塊指向無類型內(nèi)存的變量撩荣。

int a = 0;
auto it = &a;
cout << *it << endl;

BigInteger

import java.math.BigInteger;
import java.util.*;

public class test {
public static void main(String args[]){
BigInteger
a = new BigInteger("32"),
m = new BigInteger("12");
BigDecimal b = new BigDecimal("1.0");
a = a.pow(1);
a = a.add(a);
a = a.divide(a);
a = a.mod(a);
a = a.abs();
a = a.gcd(a);
a = a.modPow(a, m);
System.out.print(a.toString()+"\n");
}
}

STL去重

sort(xs.begin(),sx.end());
xs.erase(unique(xs.begin(),xs.end()),xs.end()); //unique將同樣的元素排至vector末位铣揉,返回首個重復(fù)元素地址

STL算法離散化

思路:先排序,再刪除重復(fù)元素餐曹,然后就是索引元素離散化后對應(yīng)的值逛拱。

假定待離散化的序列為a[n],b[n]是序列a[n]的一個副本台猴,則對應(yīng)以上三步為:

sort(sub_a,sub_a+n);
int size=unique(sub_a,sub_a+n)-sub_a;//size為離散化后元素個數(shù)
for(i=0;i<n;i++)
a[i]=lower_bound(sub_a,sub_a+size,a[i])-sub_a + 1;//k為b[i]經(jīng)離散化后對應(yīng)的值

對于第3步朽合,若離散化后序列為0, 1, 2, ..., size - 1則用lower_bound,從1, 2, 3, ..., size則用upper_bound饱狂,其中l(wèi)ower_bound返回第1個不小于b[i]的值的指針曹步。

而upper_bound返回第1個大于b[i]的值的指針,當然在這個題中也可以用lower_bound然后再加1得到與upper_bound相同結(jié)果休讳,兩者都是針對以排好序列讲婚。使用STL離散化大大減少了代碼量且結(jié)構(gòu)相當清晰。

其他

Vim 配置

set nu
set mouse=a
set cursorline
set confirm
set tabstop=4
set smarttab
set shiftwidth=4
set smartindent
set cindent
set nobackup
set matchtime=1
set showmatch
set setnocompatible

colo evening

syntax on
syntax enable

G++ 運行

g++ a.cpp
./a.out
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末俊柔,一起剝皮案震驚了整個濱河市筹麸,隨后出現(xiàn)的幾起案子活合,更是在濱河造成了極大的恐慌,老刑警劉巖物赶,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件白指,死亡現(xiàn)場離奇詭異,居然都是意外死亡酵紫,警方通過查閱死者的電腦和手機侵续,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來憨闰,“玉大人状蜗,你說我怎么就攤上這事○亩” “怎么了轧坎?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長泽示。 經(jīng)常有香客問我缸血,道長,這世上最難降的妖魔是什么械筛? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任捎泻,我火速辦了婚禮,結(jié)果婚禮上埋哟,老公的妹妹穿的比我還像新娘笆豁。我一直安慰自己,他們只是感情好赤赊,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布闯狱。 她就那樣靜靜地躺著,像睡著了一般抛计。 火紅的嫁衣襯著肌膚如雪哄孤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天吹截,我揣著相機與錄音瘦陈,去河邊找鬼。 笑死波俄,一個胖子當著我的面吹牛晨逝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弟断,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼咏花,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起昏翰,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤苍匆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棚菊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浸踩,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年统求,在試婚紗的時候發(fā)現(xiàn)自己被綠了检碗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡码邻,死狀恐怖折剃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情像屋,我是刑警寧澤怕犁,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站己莺,受9級特大地震影響奏甫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凌受,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一阵子、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧胜蛉,春花似錦挠进、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至解虱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間漆撞,已是汗流浹背殴泰。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留浮驳,地道東北人悍汛。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像至会,于是被迫代替她去往敵國和親离咐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗。 張土汪:刷leetcod...
    土汪閱讀 12,740評論 0 33
  • 樹形動態(tài)規(guī)劃宵蛀,顧名思義就是樹+DP昆著,先分別回顧一下基本內(nèi)容吧:動態(tài)規(guī)劃:問題可以分解成若干相互聯(lián)系的階段,在每一個...
    Mr_chong閱讀 1,477評論 0 2
  • 一年級語文上冊生字表 生字表一(共400字) 啊(ā)愛(ài)安(ān)岸(àn)爸(bà)八(bā)巴(bā)...
    meychang閱讀 2,773評論 0 6
  • 總核數(shù) = 物理CPU個數(shù) X 每顆物理CPU的核數(shù)總邏輯CPU數(shù) = 物理CPU個數(shù) X 每顆物理CPU的核數(shù) ...
    Cursor_fei閱讀 5,490評論 0 2
  • 追番神作不可缺少《海賊王》接谨!小叮追了海賊王多年,不敢說集集都準時看塘匣,但到目前為止動畫和漫畫還是啃了好十幾年脓豪,所以今...
    愛叮叮閱讀 1,436評論 1 1