【赛前复习】 某憨子的T1、T2专训
2021牛客OI赛前集训营-提高组(第六场)
旋律的总数
没意思,
点击查看代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int t, n, m, ans;
int qpow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = res * a % mod;
b >>= 1, a = a * a % mod;
}
return res;
}
signed main() {
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
scanf("%lld", &t);
while(t --) {
scanf("%lld %lld", &n, &m);
ans = qpow(m, n - 1);
printf("%lld\n", ans);
}
return 0;
}
最佳位置
可以将其看作连续一段未选座位看作一条线段,
选座位就相当于,每次找出最长的一段,均分成两个线段即可
离开就是,当前座位的左右两条线段合并
用 set 维护
我是屑。
点击查看代码
#include<cstdio>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int N = 3e5 + 5;
int n, m, a[N], ans[N], pre[N], nex[N], pos[N];
bool vis[N];
struct node {
int l, r, pos, len;
bool operator < (const node &b) const {
return len == b.len ? pos < b.pos : len > b.len;
}
void init() {
int tmp = r - l + 1;
pos = l + tmp / 2;
if(!(tmp & 1)) pos --;
len = pos - l + 1;
}
};
set<node> st;
map<int, int> mp;
int main() {
scanf("%d %d", &n, &m);
st.insert((node){1, n, 1, n});//初始化
nex[0] = n + 1, pos[m + 1] = n + 1, mp[0] = 0, mp[n + 1] = m + 1;//设界限
int x;
for(int i = 1; i <= 2 * m; i ++) {
scanf("%d", &x);
if(vis[x]) {//离开
node tmp, res;
tmp.l = pos[pre[x]], tmp.r = pos[nex[x]] - 1;//左右的两条线段
if(tmp.l == 1) tmp.pos = 1, tmp.len = tmp.r;// 不用取中点,直接计算
else if(tmp.r == n) tmp.pos = n, tmp.len = n - tmp.l + 1;//同上
else tmp.init();// 计算 tmp 的各个变量
if(tmp.l <= pos[x] - 1) {
res.l = tmp.l, res.r = pos[x] - 1;
res.init(), st.erase(*st.find(res));
}
if(pos[x] + 1 <= tmp.r) {
res.l = pos[x] + 1, res.r = tmp.r;
res.init(), st.erase(*st.find(res));
}
st.insert(tmp);
nex[pre[x]] = nex[x], pre[nex[x]] = pre[x];
pos[x] = nex[x] = pre[x] = 0;
}
else {//选座位
vis[x] = 1;
node tmp = *st.begin(), res;
st.erase(st.begin());
pos[x] = tmp.pos;
res.l = tmp.l, res.r = pos[x] - 1;
if(res.l <= res.r) {
if(res.l == 1) res.len = res.r, res.pos = 1;
else res.init();
st.insert(res);
}
res.l = pos[x] + 1, res.r = tmp.r;
if(res.l <= res.r) {
if(res.r == n) res.len = n - res.l + 1, res.pos = n;
else res.init();
st.insert(res);
}
ans[x] = pos[x];
pre[x] = mp[tmp.l - 1], nex[x] = mp[tmp.r + 1];
nex[pre[x]] = x, pre[nex[x]] = x;
mp[pos[x]] = x;
}
}
for(int i = 1; i <= m; i ++) printf("%d\n", ans[i]);
return 0;
}
牛客提高组第五场
智乃的差分
也不知道过没过。。。
分类讨论,就是需要考虑的情况有点多。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 1e5 + 5;
int t, n, x, a[N], cnt, siz, tag;
struct node {
int val, tot;
node() {}
node(int x, int y) {
val = x, tot = y;
}
}b[N];
bool cmp(node x, node y) {
return x.tot > y.tot;
}
void read(int &x) {
x = 0;
int f = 1;
char s = getchar();
while(s < '0' || s > '9') {
if(s == '-') f = -1;
s = getchar();
}
while(s <= '9' && s >= '0') x = x * 10 + s - '0', s = getchar();
x *= f;
}
int main() {
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
read(t);
while(t --) {
read(n), read(x);
for(int i = 1; i <= n; i ++) read(a[i]);
sort(a + 1, a + 1 + n);
if(x < 0) {
puts("yes");
for(int i = 1; i <= n; i ++) printf("%d ", a[i]);
puts("");
}
else if(x == 0) {
cnt = tag = 0, a[0] = a[1];
for(int i = 1; i <= n; i ++) {
if(a[i] == a[i - 1]) {
cnt ++;
if(cnt > (n + 1) / 2) {
tag = 1;
break;
}
}
else cnt = 1;
}
if(cnt > (n + 1) / 2) tag = 1;
if(tag) {
puts("no");
continue;
}
b[siz = 1] = (node) {a[1], 1};
for(int i = 2; i <= n; i ++) {
if(a[i] != a[i - 1]) {
b[++siz] = (node) {a[i], 1};
}
else b[siz].tot ++;
}
sort(b + 1, b + 1 + siz, cmp);
if(b[1].val == 0) {
if(b[1].tot * 2 == n + 1) {
puts("no");
continue;
}
swap(b[1], b[2]);
}
puts("yes"), tag = -1;
for(int i = 1; i <= siz; i ++) {
while(b[i].tot) {
if(tag + 2 > n) tag = 0;
tag += 2, b[i].tot --;
a[tag] = b[i].val;
}
}
for(int i = 1; i <= n; i ++) printf("%d ", a[i]);
puts("");
}
else {
if(a[n] != x) {
puts("yes");
for(int i = n; i; i --) printf("%d ", a[i]);
puts("");
}
else {
int j = n - 1;
while(a[j] == a[n] && j >= 1) j --;
if(!j || a[j] == 0) puts("no");
else {
swap(a[n], a[j]);
puts("yes");
for(int i = n; i; i --) printf("%d ", a[i]);
puts("");
}
}
}
}
return 0;
}
牛牛的旅行
菜死了
给定一棵树,树上任意一条长度不为 1的路径贡献为 路径上的最大点权值 减去 其路径长度。 求贡献之和。
并查集 + 树上贡献统计。
首先,边权和点权可以分开计算,
边用 \(dfs\) 跑一遍,记录每个点的子树大小,合并的时候 加上 \(siz *(n - siz)\) 即可。
点权, 先存起来从小到大排个序, 再用并查集思想维护 每个块的大小。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
const int N = 1e6 + 5, mod = 1e9 + 7;
int n, ans, fa[N], siz[N], sum[N];
int tot, head[N], to[N << 1], nex[N << 1];
bool vis[N];
struct node {
int val, id;
}tr[N];
bool cmp(node x, node y) {
return x.val < y.val;
}
void add(int x, int y) {
to[++tot] = y, nex[tot] = head[x], head[x] = tot;
}
int find(int x) {
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void dfs(int x, int f) {
int ver; siz[x] = 1;
for(int i = head[x]; i; i = nex[i]) {
ver = to[i];
if(ver == f) continue;
dfs(ver, x);
siz[x] += siz[ver];
ans = (ans - siz[ver] * (n - siz[ver]) % mod + mod) % mod;
}
}
void connect(int x, int y) {
int f = find(x), ff = find(y);
if(f != ff) {
sum[f] += sum[ff];
fa[ff] = f;
}
}
signed main() {
scanf("%lld", &n);
for(int i = 1; i <= n; i ++) scanf("%lld", &tr[i].val), tr[i].id = fa[i] = i, sum[i] = 1;
int u, v;
for(int i = 1; i < n; i ++) {
scanf("%lld %lld", &u, &v);
add(u, v), add(v, u);
}
dfs(1, 0);
sort(tr + 1, tr + 1 + n, cmp);
int ver;
for(int i = 1; i <= n; i ++) {
for(int j = head[tr[i].id]; j; j = nex[j]) {
ver = to[j];
if(vis[ver]) {
u = find(tr[i].id), v = find(ver);
ans = (ans + tr[i].val * sum[u] % mod * sum[v] % mod) % mod;
connect(tr[i].id, ver);
}
}
vis[tr[i].id] = 1;
}
printf("%lld", ans * 2 % mod);
return 0;
}
牛客提高组第四场
最终测试
阿西吧,期望水题?
因为一个选手的得分情况只有 \(4\) 种, 直接算出来就好。
最后的 \(/16\) 是因为 每两个选手 各有四种情况, 概率均分。
直接计算对于每种取值,有多少种取值大于它。(排第几名)
注意要减去自身可能大于的情况。
水……
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int N = 1e5 + 5;
int n, cnt, val[N << 2], v[2], a[N][4], ans[N];
bool cmp(int x, int y) {
return x > y;
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%d %d", &v[0], &v[1]);
a[i][0] = 0, a[i][1] = v[0], a[i][2] = v[1], a[i][3] = v[1] + v[0];
for(int j = 0; j < 4; j ++) val[++cnt] = a[i][j];
}
sort(val + 1, val + 1 + cnt, cmp);
for(int i = 1; i <= n; i ++) {
for(int j = 0; j < 4; j ++) {
int id = lower_bound(val + 1, val + 1 + cnt, a[i][j], cmp) - val - 1;
for(int k = 0; k < 4; k ++) {
if(a[i][k] > a[i][j]) id --;
}
ans[i] += id;
}
}
for(int i = 1; i <= n; i ++) {
printf("%f\n", ans[i] / 16.0 + 1.0);
}
return 0;
}
空间跳跃
角谷猜想是什么神笔东西。虽然我不知道为什么它是对的,就很妙
正难则反嘛
倒退就是 从 n 到 1
根据定理,正整数直接可以推到 1
负整数 在根据操作 1 搞成正整数, 再搞到 1 就可以了。
我不理解!
#include<cstdio>
#include<algorithm>
using namespace std;
int q, d, l, n, cnt, a[2000];
int main() {
scanf("%d %d %d", &q, &d, &l);
while(q --) {
scanf("%d", &n);
a[cnt = 1] = n;
while(!n && n != -1 && n != -5 && n != -17) {
if(n & 1) n = n * 3 + 1;
else n /= 2;
a[++cnt] = n;
}
while(n <= 0) n += d, a[++cnt] = n;
while(n != 1) {
if(n & 1) n = n * 3 + 1;
else n /= 2;
a[++cnt] = n;
}
printf("%d\n", cnt - 1);
for(int i = cnt; i; i --) printf("%d ", a[i]);
puts("");
}
return 0;
}
树网的核
依旧是很恶心的题面
不愧是 \(CCF\) 语言((
直接根据树的直径的性质来搞就好了。
可以肯定的是,非直径上的点到直径的距离的最大值一定是最小的
所以先跑两遍 \(dfs\) 求出直径,在跑一遍非直径,取最大值就好了。
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 305;
int n, m, tot, ans = 1e9, head[N], nex[N << 1], to[N << 1], w[N << 1];
void add(int x, int y, int z) {
to[++tot] = y, nex[tot] = head[x], head[x] = tot, w[tot] = z;
}
bool tag[N];
int fa[N], dis[N], mx;
void dfs(int x, int f) {
fa[x] = f; int ver;
if(dis[x] > dis[mx]) mx = x;
for(int i = head[x]; i; i = nex[i]) {
ver = to[i];
if(tag[ver] || ver == f) continue;
dis[ver] = dis[x] + w[i];
dfs(ver, x);
}
}
int main() {
scanf("%d %d", &n, &m);
int u, v, ww;
for(int i = 1; i < n; i ++) {
scanf("%d %d %d", &u, &v, &ww);
add(u, v, ww), add(v, u, ww);
}
dis[1] = 1, dfs(1, 0), dis[mx] = 0, dfs(mx, 0);
u = mx;
for(int i = u, j = u; i; i = fa[i]) {
while(dis[j] - dis[i] > m) j = fa[j];
ans = min(ans, max(dis[u] - dis[j], dis[i]));
}
for(int i = u; i; i = fa[i]) tag[i] = 1;
for(int i = u; i; i = fa[i]) {
mx = i, dis[i] = 0;
dfs(i, fa[i]);
}
for(int i = 1; i <= n; i ++) ans = max(ans, dis[i]);
printf("%d\n", ans);
return 0;
}