D1T1 铺设道路

  在场上并没有想到积木大赛这道原题。

  差分之后可以把在$[l, r]$这段区间$ - 1$变成在$l$处$ - 1$,在$r + 1$处$ + 1$,然后最终目标是使$\forall i \in [1, n] \ \Delta d_i == 0$成立。就想着把正负数配一配对,然后输出了正数绝对值和负数绝对值的$max$,这导致了我的代码非常鬼畜。

  出来之后发现正数绝对值一定大于等于负数绝对值,要不然就会出现$d_i < 0$的情况。

  时间复杂度$O(n)$。

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 1e5 + ; int n;
ll a[N], b[N]; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} ll abs(ll x) {
return x > ? x : -x;
} inline ll max(ll x, ll y) {
return x > y ? x : y;
} int main() {
// freopen("road.in", "r", stdin);
// freopen("road.out", "w", stdout); read(n);
for(int i = ; i <= n; i++) {
read(a[i]);
b[i] = a[i] - a[i - ];
} /* for(int i = 1; i <= n; i++)
printf("%lld ", b[i]);
printf("\n"); */ ll ps = 0LL, ne = 0LL;
for(int i = ; i <= n; i++) {
if(b[i] > ) ps += b[i];
else ne -= b[i];
} printf("%lld\n", max(ne, ps));
return ;
}

road

D1T2 货币系统

  一开始觉得是一道数学题,后来回过头来发现应该可以完全背包,先写了$80$分的暴力,然后又想了一下可以用分治优化到$O(Tnlogna_i)$,就写了一下然后拍了拍,最后在少爷机上$AC$了。

  用$solve(l, r)$表示不考虑$[l, r]$这段区间内的货币的情况,然后在向下算的时候每一次做一半就好了。

  出来之后发现就是个$sb$排序。

  时间复杂度$O(Tna_i)$,放上分治的代码。

#include <cstdio>
#include <cstring>
using namespace std; const int N = ;
const int M = ;
const int Lg = ; int testCase, n, mx = , a[N], ans;
bool f[Lg][M]; inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} void solve(int l, int r, int dep) {
if(l == r) {
if(f[dep][a[l]]) ans--;
return;
} ++dep;
for(int i = ; i <= mx; i++) f[dep][i] = f[dep - ][i]; int mid = ((l + r) >> );
for(int i = l; i <= mid; i++)
for(int j = a[i]; j <= mx; j++)
f[dep][j] |= f[dep][j - a[i]];
solve(mid + , r, dep); for(int i = ; i <= mx; i++) f[dep][i] = f[dep - ][i];
for(int i = mid + ; i <= r; i++)
for(int j = a[i]; j <= mx; j++)
f[dep][j] |= f[dep][j - a[i]];
solve(l, mid, dep);
} int main() {
// freopen("money.in", "r", stdin);
// freopen("money.out", "w", stdout); for(read(testCase); testCase--; ) {
read(n);
mx = ;
for(int i = ; i <= n; i++) {
read(a[i]);
chkMax(mx, a[i]);
} for(int i = ; i <= mx; i++) f[][i] = ;
f[][] = ; ans = n;
solve(, n, ); printf("%d\n", ans);
}
return ;
}

money

D1T3 赛道修建

  挺简单的第三题。首先外层二分,然后把一个点的所有儿子存下来,贪心从小到大匹配,在保证对答案的贡献最大的情况下使延伸到父亲处理的链尽量长。我在考场上写了一个常数巨大的$multiset$,也能跑过。

  其实也可以再二分一个能向上的最长链然后看看答案会不会变差就行了,这样子常数比较优秀。

  仍然不会更高级的解法。

  时间复杂度$O(nlog^2n)$。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std; const int N = 5e4 + ;
const int inf = << ; int n, m, cnt, lim, tot = , head[N], f[N];
multiset <int> s[N]; struct Edge {
int to, nxt, val;
} e[N << ]; inline void add(int from, int to, int val) {
e[++tot].to = to;
e[tot].val = val;
e[tot].nxt = head[from];
head[from] = tot;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} /* inline int getPos(int which, int siz, int val) {
val = lim - val;
int ln = 0, rn = siz, mid, res = -1;
for(; ln <= rn; ) {
mid = ((ln + rn) >> 1);
if(vec[which][mid] >= val) res = mid, rn = mid - 1;
else ln = mid + 1;
}
return res;
} */ /* void dfs(int x, int fat) {
vec[x].clear();
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x);
vec[x].push_back(f[y] + e[i].val);
} sort(vec[x].begin(), vec[x].end());
int vecSiz = vec[x].size() - 1;
for(; vecSiz; --vecSiz) {
if(vecSiz == -1) break;
if(vec[x][vecSiz] < lim) break;
++cnt;
}
for(int i = 0; i <= vecSiz; i++) tag[i] = 0;
for(int i = vecSiz; i > 0; i--) {
int pos = getPos(x, i - 1, vec[x][i]);
if(pos != -1) tag[pos] = 1, tag[i] = 1, ++cnt;
} int res = 0;
for(int i = 0; i <= vecSiz; i++)
if(tag[i]) tag[i] = 0;
else chkMax(res, vec[x][i]); f[x] = res;
} */ void dfs(int x, int fat) {
// s[x].clear();
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x);
s[x].insert(f[y] + e[i].val);
} for(; !s[x].empty(); ) {
multiset <int> :: iterator it = (--s[x].end());
if((*it) >= lim) {
++cnt;
s[x].erase(it);
} else break;
} int res = ;
for(; !s[x].empty(); ) {
multiset <int> :: iterator p1 = s[x].begin();
int tmp = (*p1);
s[x].erase(p1);
multiset <int> :: iterator p2 = s[x].lower_bound(lim - tmp); if(p2 == s[x].end()) {
chkMax(res, tmp);
} else {
cnt++;
s[x].erase(p2);
}
} f[x] = res;
} inline bool chk(int mid) {
lim = mid, cnt = ;
for(int i = ; i <= n; i++) f[i] = ;
dfs(, );
return cnt >= m;
} int main() {
// freopen("track.in", "r", stdin);
// freopen("track.out", "w", stdout); read(n), read(m);
int ln = , rn = , mid, res = inf;
for(int x, y, v, i = ; i < n; i++) {
read(x), read(y), read(v);
add(x, y, v), add(y, x, v);
rn += v;
} for(; ln <= rn; ) {
mid = (ln + rn) / ;
if(chk(mid)) ln = mid + , res = mid;
else rn = mid - ;
} printf("%d\n", res);
return ;
}

track

D2T1 旅行

  原来以为图论跑到$T1$来了,没想到最后还是个树。

  先考虑树的部分分,发现只有走完一个点的所有子树之后才能向上走,所以每次贪心地走最小的子树就好了;然后考虑基环树的部分分,看到$n$不超过$5000$,直接把环找出来然后断一断走一走取个最小就好了。

  场上写出了一个$bug$但只被卡了$4$分。

  树的话时间复杂度是$O(nlogn)$,基环树是$O(n^2)$。

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std; const int N = ;
const int inf = << ; int n, m, cnt = , ans[N];
vector <int> e[N]; inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} namespace Solve1 { void dfs(int x, int fat) {
int vecSiz = e[x].size();
for(int i = ; i < vecSiz; i++) {
int y = e[x][i];
if(y == fat) continue;
ans[++cnt] = y;
dfs(y, x);
}
} void work() {
ans[++cnt] = ;
dfs(, ); for(int i = ; i <= n; i++) {
printf("%d", ans[i]);
if(i == n) putchar('\n');
else putchar(' ');
}
} } namespace Solve2 {
int top, stk[N], sum, cir[N], dx, dy, res[N];
bool inc[N], vis[N], flag = ; void getCir(int x, int fat) {
// int pre = top;
if(flag) return;
stk[++top] = x, vis[x] = ;
int vecSiz = e[x].size();
for(int i = ; i < vecSiz; i++) {
int y = e[x][i];
if(y == fat) continue;
if(vis[y]) {
flag = ;
sum = ;
for(; stk[top] != y; --top) {
inc[stk[top]] = ;
vis[stk[top]] = ;
cir[++sum] = stk[top];
}
inc[y] = , cir[++sum] = y, vis[y] = , top--;
return;
} else getCir(y, x);
}
// top = pre;
if(vis[x]) --top, vis[x] = ;
} inline bool bet() {
for(int i = ; i <= n; i++)
if(res[i] != ans[i]) return res[i] < ans[i];
return ;
} void dfs(int x, int fat) {
int vecSiz = e[x].size();
for(int i = ; i < vecSiz; i++) {
int y = e[x][i];
if(y == fat) continue;
if((x == dx && y == dy) || (x == dy && y == dx)) continue;
res[++cnt] = y;
dfs(y, x);
}
} void work() {
top = ;
getCir(, ); /* for(int i = 1; i <= sum; i++)
printf("%d ", cir[i]);
printf("\n"); */ for(int i = ; i <= n; i++) ans[i] = inf; for(int i = ; i < sum; i++) {
dx = cir[i], dy = cir[i + ];
res[cnt = ] = ;
dfs(, );
if(bet()) {
for(int j = ; j <= n; j++)
ans[j] = res[j];
}
}
dx = cir[], dy = cir[sum];
res[cnt = ] = ;
dfs(, );
if(bet()) {
for(int j = ; j <= n; j++)
ans[j] = res[j];
} for(int i = ; i <= n; i++) {
printf("%d", ans[i]);
if(i == n) putchar('\n');
else putchar(' ');
}
} } int main() {
// freopen("travel.in", "r", stdin);
// freopen("travel.out", "w", stdout); // freopen("testdata.in", "r", stdin); read(n), read(m);
for(int x, y, i = ; i <= m; i++) {
read(x), read(y);
e[x].push_back(y), e[y].push_back(x);
} for(int i = ; i <= n; i++)
sort(e[i].begin(), e[i].end()); if(m == n - ) Solve1 :: work();
else Solve2 :: work(); return ;
}

travel

D2T2 填数游戏

  我到现在都还认为这是一道打表题。

  放上大神的状压题解   戳这里

  首先写个暴力写打出$(n, n)$的表$(n \leq 8)$,然后就靠这三条性质求答案:

  1、$(n, m) = (m, n)$。

  2、$(n, m) = (n, m - 1) * 3$ $(m > n)$。

  3、$$ (n, n + 1) = \left\{\begin{matrix}
    (n, n) * 3 & (n \leq 3) \\ 
    (n, n) * 3 - 2^n * 3& (n \geq 4) 
    \end{matrix}\right. $$

  时间复杂度$O(logn)$。

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = ;
const ll P = 1e9 + ;
const ll base[N] = {, , , , , , , , , }; int n, m; template <typename T>
inline void swap(T &x, T &y) {
T t = x; x = y; y = t;
} inline ll fpow(ll x, ll y) {
ll res = 1LL;
for(; y > ; y >>= ) {
if(y & ) res = res * x % P;
x = x * x % P;
}
return res;
} int main() {
scanf("%d%d", &n, &m);
if(n > m) swap(n, m);
if(n == ) return printf("%lld\n", fpow(2LL, m)), ;
if(n == m) return printf("%lld\n", base[n]), ;
ll ans = 1LL;
if(n > ) ans = (3LL * base[n] % P - 3LL * fpow(2LL, n) % P + P) % P;
else ans = base[n] * 3LL % P;
ans = ans * fpow(3LL, m - n - ) % P;
printf("%lld\n", ans);
return ;
}

game

D2T3 保卫王国

  为什么会有动态$dp$这种东西出现啊啊啊啊啊啊。

  我还是只会倍增的做法。用$h_{x, 0/1}$表示$x$的子树中选/不选$x$的最小代价,用$g_{x, 0/1}$表示$x$到根的链上不算$x$的子树$x$选/不选的最小代价,用$f_{x, i, 0/1, 0/1}$表示从$x$向上跳$2^i$的这条链上不算$x$的子树其他子树的最小代价。

  然后剩下看代码吧,感觉代码肯定比我讲得清楚。

  时间复杂度$O(nlogn)$,常数巨大。

#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef pair <int, int> pin; const int N = 1e5 + ;
const int Lg = ;
const ll inf = 1LL << ; int n, qn, tot = , head[N], fa[N][Lg], dep[N];
ll a[N], h[N][], f[N][Lg][][], g[N][];
map <pin, int> ex; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void chkMin(T &x, T y) {
if(y < x) x = y;
} inline ll min(ll x, ll y) {
return x > y ? y : x;
} void dp1(int x, int fat) {
h[x][] = , h[x][] = a[x];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dp1(y, x);
h[x][] += h[y][];
h[x][] += min(h[y][], h[y][]);
}
} void dp2(int x, int fat) {
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
g[y][] = g[x][] + h[x][] - min(h[y][], h[y][]);
g[y][] = min(g[y][], h[x][] - h[y][] + g[x][]);
dp2(y, x);
}
} void dfs(int x, int fat, int depth) {
fa[x][] = fat, dep[x] = depth; f[x][][][] = inf, f[x][][][] = h[fat][] - min(h[x][], h[x][]);
f[x][][][] = h[fat][] - h[x][], f[x][][][] = h[fat][] - min(h[x][], h[x][]);
for(int i = ; i <= ; i++) {
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int u = ; u < ; u++)
for(int v = ; v < ; v++) {
f[x][i][u][v] = inf;
for(int k = ; k < ; k++)
chkMin(f[x][i][u][v], f[x][i - ][u][k] + f[fa[x][i - ]][i - ][k][v]);
}
} for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x, depth + );
}
} inline void solve(int x, int tx, int y, int ty) {
if(dep[x] < dep[y])
swap(x, y), swap(tx, ty); ll resx[] = {inf, inf}, resy[] = {inf, inf}, tox[], toy[];
resx[tx] = h[x][tx], resy[ty] = h[y][ty]; for(int i = ; i >= ; i--)
if(dep[fa[x][i]] >= dep[y]) {
tox[] = tox[] = inf;
for(int u = ; u < ; u++)
for(int v = ; v < ; v++)
chkMin(tox[u], resx[v] + f[x][i][v][u]);
resx[] = tox[], resx[] = tox[];
x = fa[x][i];
} if(x == y) {
printf("%lld\n", resx[ty] + g[y][ty]);
return;
} for(int i = ; i >= ; i--)
if(fa[x][i] != fa[y][i]) {
tox[] = tox[] = inf;
for(int u = ; u < ; u++)
for(int v = ; v < ; v++)
chkMin(tox[u], resx[v] + f[x][i][v][u]);
resx[] = tox[], resx[] = tox[]; toy[] = toy[] = inf;
for(int u = ; u < ; u++)
for(int v = ; v < ; v++)
chkMin(toy[u], resy[v] + f[y][i][v][u]);
resy[] = toy[], resy[] = toy[]; x = fa[x][i], y = fa[y][i];
} int z = fa[x][];
ll res = h[z][] - h[x][] - h[y][] + g[z][] + resx[] + resy[];
chkMin(res, h[z][] - min(h[x][], h[x][]) - min(h[y][], h[y][]) +
g[z][] + min(resx[], resx[]) + min(resy[], resy[]));
printf("%lld\n", res);
} int main() {
read(n), read(qn);
char typ[]; scanf("%s", typ);
for(int i = ; i <= n; i++) read(a[i]);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
ex[pin(x, y)] = ex[pin(y, x)] = ;
} dp1(, ), dp2(, ), dfs(, , ); for(int x, tx, y, ty; qn--; ) {
read(x), read(tx), read(y), read(ty);
if(ex.find(pin(x, y)) != ex.end() && !tx && !ty) puts("-1");
else solve(x, tx, y, ty);
} return ;
}

defense

NOIP2018 解题笔记的更多相关文章

  1. 《剑指offer》解题笔记

    <剑指offer>解题笔记 <剑指offer>共50题,这两周使用C++花时间做了一遍,谨在此把一些非常巧妙的方法.写代码遇到的难点.易犯错的细节等做一个简单的标注,但不会太过 ...

  2. 122. Best Time to Buy and Sell Stock(二) leetcode解题笔记

    122. Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price ...

  3. 110.Balanced Binary Tree Leetcode解题笔记

    110.Balanced Binary Tree Given a binary tree, determine if it is height-balanced. For this problem, ...

  4. 2016/9/21 leetcode 解题笔记 395.Longest Substring with At Least K Repeating Characters

    Find the length of the longest substring T of a given string (consists of lowercase letters only) su ...

  5. LeetCode解题笔记 - 3. Longest Substring Without Repeating Characters

    Given a string, find the length of the longest substring without repeating characters. Examples: Giv ...

  6. LeetCode解题笔记 - 2. Add Two Numbers

    2. Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. ...

  7. 解题笔记——NIT 遥远的村庄

    某个小镇有 N 个村庄,村庄编号1-N,给出 M 条单向道路,不存在环,即不存在 村庄A可以到达村庄B 且 村庄B也可以到达村庄A的情况.如果村庄A与村庄B之间存在一条单向道路,则说村庄A和村庄B之间 ...

  8. HDU-5902-GCD is Funny解题笔记

    Alex has invented a new game for fun. There are n integers at a board and he performs the following ...

  9. CTF实验吧-WEB题目解题笔记(1)简单的登陆题

    1.简单的登陆题 解题链接: http://ctf5.shiyanbar.com/web/jiandan/index.php  Burp抓包解密 乱码,更换思路.尝试id intruder 似乎也没什 ...

随机推荐

  1. JDBC 3 通过PreparedStatement 对数据库进行增删改查

    下面程序沿用上面的封装. 1 插入数据 public boolean ChaRu3(User user){ boolean flag=true; Connection conn=null; Prepa ...

  2. Robot Framework接口测试(1)

    RF是做接口测试的一个非常方便的工具,我们只需要写好发送报文的脚本,就可以灵活的对接口进行测试. 做接口测试我们需要做如下工作: 1.拼接发送的报文 2.发送请求的方法 3.对结果进行判断 我们先按步 ...

  3. Django--django-admin.py on windows does not work

    使用命令:Python django-admin.py startproject projectname 使用django-admin.py startapp myblog没有创建新的app,使用下面 ...

  4. Java问题:中间件是什么

    和朋友聊天时被问到中间件是什么?一时有点语赛,感觉熟悉这个概念,但又完全不知道如何清楚的向别人讲这些. 网络上搜了一下,也没找到让自己很认可的说法,有的说非业务的技术类组件,是操作系统之上和业务逻辑之 ...

  5. 洛谷 1600 (NOIp2016) 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看TJ:https://blog.csdn.net/clove_unique/article/detail ...

  6. spring mvc加了@produces注解后报406

    问题背景:调用http的post接口返回一个String类型的字符串时中文出现乱码,定位出问题后在@RequestMapping里加produces注解produces = "applica ...

  7. Linux环境抓包命令

    有时候有些接口调用问题不好定位或者日志不够详细,那么我们往往会选择通过抓包来看详细的通讯过程.抓包有相关软件,这里说如何直接在环境里抓.假如现在我们在 Linux 下部署了 Tomcat 服务器,端口 ...

  8. Linux LED字符设备驱动

    // 申请IO资源 int gpio_request(unsigned gpio, const char *label); // 释放IO资源 void gpio_free(unsigned gpio ...

  9. Linux安装微信

    地址:http://www.toutiao.com/i6362126617556288001/#6649976-tsina-1-90079-4471e2b057b5019ad452c722f04bba ...

  10. Server Error in '/' Application. IIS拒绝访问

    昨天将改好的网站重写发布更新了一下,就出现这种问题.那是一个头两个大呀. 刚开始以为是文件夹没有IIS的访问权限,在网上找的好多答案都是temp文件夹没有权限,,但将IIS的权限都加上后,还是不行,同 ...