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. 调试SPRING MVC(或者整合SSH)的时候遇到了org/objectweb/asm/Type

    调试SPRING MVC(或者整合SSH)的时候遇到了org/objectweb/asm/Type 解决方法1: 原因是Spring中的cglib-nodep-2.x.x.jar与Hibernate中 ...

  2. gradle wrapper 简单使用

    其实就是对于gradle 的一个包装,保证了项目版本的一致,同时减少配置   1. 生成wrapper // 使用gradle wrapper 命令 gradle wrapper 输出效果如下: [r ...

  3. Oracle创建实例

    1.打开database configuration assistant 2.下一步 3.下一步 4.完成 5.添加完密码后,点击关闭.  

  4. Linux 绑定双网卡

    1.立即关闭iptables并禁用开机自启动[root@mysql01 ~]# /etc/init.d/iptables stop[root@mysql01 ~]# chkconfig iptable ...

  5. Toolbar使用

    原文地址 http://www.cnblogs.com/Dentist/p/4370176.html Android4.0出现的Actionbar提供了同意方便的导航管理.很大程度的统一了Androi ...

  6. SQL语言分为五大类

    SQL语言分为五大类:DDL(数据定义语言) - Create.Alter.Drop 这些语句自动提交,无需用Commit提交.DQL(数据查询语言) - Select 查询语句不存在提交问题.DML ...

  7. C#将字符串数组转换为以逗号分隔的字符串

    , tyt, gff }; string str=string.Join(",",array);

  8. (转)C# Socket简单例子(服务器与客户端通信)

    本文转载自:http://blog.csdn.net/andrew_wx/article/details/6629721 这个例子只是简单实现了如何使用 Socket 类实现面向连接的通信. 注意:此 ...

  9. About CoffeeScript

    本篇文章是对CoffeeScript做一个初步的了解.入门的学习笔记. 什么是CoffeeScript 一种新编程语言,是一套JavaScript的转译语言,可编译成高效的JavaScript.还可以 ...

  10. PS相关技术

    PS相关长时间不用就忘记了,做个笔记,记录下来 (1)复制图层,可以将图层复制到另外的图层里去,这样,多个图层就可以编辑了 (2)通过建立选区,可以选择右键,通过剪切的图层,通过复制的图层将图片抠出来 ...