A Social Distancing
#include
using namespace std;
const int N = 1e6 + 10;
int res[N], tot;
int n, m, k;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> m;
tot = 0;
while (n && m) {
if (n < m) swap(n, m);
for (int i = 1; i <= m; i++) {
res[++tot] = m;
}
n -= m;
}
cout << tot << endl;
for (int i = 1; i <= tot; i++) {
cout << res[i] << (i == tot ? "\n" : " ");
}
}
return 0;
}
要搞定这道题的几个神仙操作:
F [ x ] = m i n ( F [ x ] , 0 ) F[x]=min(F[x],0) F[x]=min(F[x],0) 相当于开一个数组,每次执行该操作时查询当前 F ( x ) F(x) F(x) 的值,如果大于0,则累加当前值,最后查询时一起减掉
∑ i = 1 c n t w i − d i s ( x i , y ) = ∑ i = 1 c n t ( w i − d e p [ x i ] − d e p [ y ] + 2 d e p [ l c a ( x i , y ) ] ) \sum_{i=1}^{cnt}w_i-dis(x_i,y)=\sum_{i=1}^{cnt}\big(w_i-dep[x_i]-dep[y]+2dep[lca(x_i,y)] \big) i=1∑cntwi−dis(xi,y)=i=1∑cnt(wi−dep[xi]−dep[y]+2dep[lca(xi,y)])
后面 dep(lca) 那部分 = 标记根节点到 x i x_i xi的路径上所有出现的点,最后统计 根节点到 y y y 的路径上这些被标记的点出现的次数
啊……学到了学到了……
#include
using namespace std;
typedef long long ll;
const int N = 1e6 + 5;
int n, m, k;
namespace chain {//树链剖分板子
vector<int> e[N];
void add(int u, int v) {
e[u].push_back(v);
e[v].push_back(u);
}
int dep[N];//深度
int f[N];//父节点
int son[N];//重儿子
int sz[N];//子树大小
void dfs1(int u, int fa) {
f[u] = fa;
dep[u] = dep[fa] + 1;
sz[u] = 1;
for (int i = 0, siz = e[u].size(); i < siz; i++) {
int v = e[u][i];
if (v != fa) {
dfs1(v, u);
sz[u] += sz[v];
if (sz[v] > sz[son[u]])
son[u] = v;
}
}
}
int dfn = 0, id[N], top[N];
void dfs2(int u, int tp) {
id[u] = ++dfn;
top[u] = tp;
if (son[u]) dfs2(son[u], tp);
for (int i = 0, siz = e[u].size(); i < siz; i++) {
int v = e[u][i];
if (v != f[u] && v != son[u]) {
dfs2(v, v);
}
}
}
}
using namespace chain;
struct segTree {
#define ls (o<<1)
#define rs (o<<1|1)
struct node {
int l, r;
int lazy;//往下传的标志 不包括本身
ll sum;
} t[N << 2];
void pushup(int o) {
t[o].sum = t[ls].sum + t[rs].sum;
}
void pushdown(int o) {
if (t[o].lazy) {
int len = t[o].r - t[o].l + 1;
t[ls].lazy += t[o].lazy;
t[rs].lazy += t[o].lazy;
t[ls].sum += 1ll * t[o].lazy * (len - (len >> 1));
t[rs].sum += 1ll * t[o].lazy * (len >> 1);
t[o].lazy = 0;
}
}
//不带数组 建树
void build(int o, int l, int r) {
t[o].l = l;
t[o].r = r;
t[o].sum = 0;
t[o].lazy = 0;
if (l == r) {
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
}
//查询[L,R]区间和
ll query(int o, int L, int R) {
if (L <= t[o].l && t[o].r <= R) {
return t[o].sum;
}
pushdown(o);
int mid = t[o].l + t[o].r >> 1;
ll res = 0;
if (L <= mid) res += query(ls, L, R);
if (R > mid) res += query(rs, L, R);
pushup(o);
return res;
}
//将[L,R]区间内的点全部+1
void update(int o, int L, int R) {
if (L <= t[o].l && t[o].r <= R) {
t[o].sum += (t[o].r - t[o].l + 1);
t[o].lazy++; // 出现次数+1
return;
}
pushdown(o);
int mid = t[o].l + t[o].r >> 1;
if (L <= mid) update(ls, L, R);
if (R > mid) update(rs, L, R);
pushup(o);
}
} ST;
//更新 u-根节点
void updRange(int u) {
while (top[u] != 1) {
ST.update(1, id[top[u]], id[u]);
u = f[top[u]];
}
ST.update(1, 1, id[u]);
}
// u-根节点求和
ll sumRange(int u) {
ll res = 0;
while (top[u] != 1) {
res += ST.query(1, id[top[u]], id[u]);
u = f[top[u]];
}
res += ST.query(1, 1, id[u]);
return res;
}
ll op_Min[N];
int main() {
int T, op, w, x, y, cnt;
ll Sum;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
dfn = 0;
for (int i = 1; i <= n; i++) {
op_Min[i] = 0;
e[i].clear();
son[i] = 0;
}
for (int i = 1; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
}
dfs1(1, 0);
dfs2(1, 1);
ST.build(1, 1, n);
Sum = 0;// ∑w -∑dep[x]
cnt = 0;// op1操作次数
while (m--) {
scanf("%d", &op);
if (op == 1) {
scanf("%d%d", &x, &w);
Sum += w - dep[x];
cnt++;
// 将x到根节点这一段路径上所有的点都+1
updRange(x);
} else if (op == 2) {
scanf("%d", &x);
// 当前x点的值
ll tmp = Sum - 1ll * cnt * dep[x] - op_Min[x] + sumRange(x) * 2;
if (tmp > 0)
op_Min[x] += tmp;
} else {//op=3
scanf("%d", &x);
printf("%lld\n", Sum - 1ll * cnt * dep[x] - op_Min[x] + sumRange(x) * 2);
}
}
}
return 0;
}
打表发现 ∑ i = 1 n i 2 = x 2 if n=1 or n=24 \sum^n_{i=1}i^2=x^2 \texttt{ if n=1 or n=24} i=1∑ni2=x2 if n=1 or n=24
#include
using namespace std;
typedef long long ll;
int main() {
int t;
scanf("%d", &t);
while (t--) {
ll n;
scanf("%lld", &n);
if (n == 1 || n == 24)
printf("Fake news!\n");
else
printf("Nobody knows it better than me!\n");
}
return 0;
}
E NeoMole Synthesis
F Tokens on the Tree
G Topo Counting
打表找规律
#include
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
/*
n=15 k=20
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0
1 1 1 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0
1 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0
1 1 1 1 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0
1 1 1 1 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0
1 1 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0
1 1 1 0 1 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0
纵向 10...1为一组
横向 每组增加一个0
整数分块
*/
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll n, k;
cin >> n >> k;
ll lim = min(k, n);
ll res = n % mod, tmp;
for (ll l = 2, r; l <= lim; l = r + 1) {
r = n / (n / l);
if (r > lim) r = lim;
// 每个完整的一组都有2个1 不完整的一组 只有1个
// 先将所有组都视为完整的 然后减去不完整的但是被多统计进去的那个1
res = (res + ((((r - l + 1) * 2) % mod) * (n / l) % mod)) % mod;
tmp = ((r - l + 1) - ((n % r) ? 0 : 1)) % mod;
res = (res + tmp) % mod;
}
if (k > n) {
res = (res + (k - n) % mod) % mod;
}
cout << res << endl;
return 0;
}
I Valuable Forests
J Pointer Analysis