弱校联合训练日常被虐惨案。by绍兴一中
hdu 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066
##Kanade’s sum##
题意:给一个由1-n随机排序组成的序列,每个数只会出现一次,现在,对于每一个子区间,他的权值为出现第k大的数,现在问这个序列总价值为多少。
拿到这题,俩队友拿nth_element和划分数狂套,卡死在区间枚举n * n的复杂度上。。
思路: 对于每一个数,我们可以从小到大枚举,当枚举到第i位数时,记录他左边k+1个比他大的,右边k+1个比他大的。然后左右两两枚举,保证左右组合出来的区间可以使那个数成为第k大的数,然后组合数学计算答案。操作完毕后,将那个数删除,用指针表示即可。那这样子操作的话,每次左右访问只需要访问2 * k次即可以知道能表示所需枚举的左右k大的区间,而全部情况也只需要线性扫描一次即可。
#include <bits/stdc++.h>
#define MAXN 500005
#define ll long long
using namespace std;
int num[MAXN], pre[MAXN], nxt[MAXN], pos[MAXN];
int rgt[100], lft[100];
int n, k;
void remove(int p) {
int tmp1 = pre[p];
int tmp2 = nxt[p];
pre[tmp2] = tmp1;
nxt[tmp1] = tmp2;
}
ll solve() {
ll ans = 0;
for (int i = 1; i <= n; i++) {
pre[i] = i - 1;
nxt[i] = i + 1;
pos[num[i]] = i;
}
num[0] = num[n + 1] = n + 1;
for (int i = 1; i <= n; i++) {
int p = pos[i];
int l = 0, r = 0;
for (int j = 0, q = p; j < k + 1 && num[q] >= i; j++, q = pre[q]) {
lft[l++] = q;
if (q == 0) {
break;
}
}
for (int j = 0, q = p; j < k + 1 && num[q] >= i; j++, q = nxt[q]) {
rgt[r++] = q;
if (q == n + 1) {
break;
}
}
int b = k - (l - 1) + 1;
int a = l - 2;
while (a >= 0 && b < r) {
ans += 1LL * (lft[a] - lft[a + 1]) * (rgt[b] - rgt[b - 1]) * i;
a--, b++;
}
remove(p);
}
return ans;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d", &num[i]);
}
printf("%lld\n", solve());
}
}
/*
1
5 2
1 3 4 5 2
33
*/
##RXD and dividing##
orz傻逼的读错题,以为是一颗生成树划分成k个不同的集合问每个集合内最短的点相加的值。可能是没认真读过斯坦纳树。
题意:给一个n - 1(不包括1)个节点的集合,你可以划分成k个两两相交为空集的集合, 定义每组的的权值为该组内所有点加编号为1的节点相互连接所经过的边的权值的和。现在问分成k组之后,所有组的和最大是多少。
思路:如果暴力去枚举点划分且用dp计算的话,时间复杂度是不够的。我们可以考虑到,想要他的总和最大,从某个点开始dfs遍历下去,对于每一个点,他最多可以被经过的次数为k次(被访问k个儿子节点),他越被访问得多,总和就越大。
那么只需要从某个点开始(直接从1开始),dfs下去,总和就等于对于每一个点他们min(儿子节点数,k) * 已经走过的权值之和。
#include <bits/stdc++.h>
#define MAXN 1000010
#define ll long long
using namespace std;
map<pair<int, int> , int> mapp;
vector<int> vec[MAXN];
int size[MAXN];
int cost[MAXN];
void addEdge(int u, int v, int w) {
mapp[make_pair(u, v)] = w;
mapp[make_pair(v, u)] = w;
vec[u].push_back(v);
vec[v].push_back(u);
}
void init() {
for (int i = 0; i < MAXN; i++) {
vec[i].clear();
}
memset(size, 0, sizeof(size));
memset(cost, 0, sizeof(cost));
mapp.clear();
}
void dfs(int u, int fa) {
int len = vec[u].size();
size[u] = 1;
for (int i = 0; i < len; i++) {
int v = vec[u][i];
if (v != fa) {
cost[v] = mapp[make_pair(v, u)];
dfs(v, u);
size[u] += size[v];
}
}
}
int main() {
int n, k, u, v, w;
while (~scanf("%d %d", &n, &k)) {
init();
for (int i = 0; i < n - 1; i++) {
scanf("%d %d %d", &u, &v, &w);
addEdge(u, v, w);
}
dfs(1, -1);
ll ans = 0;
for (int i = 2; i <= n; i++) {
ans += 1LL * min(size[i], k) * cost[i];
}
printf("%lld\n", ans);
}
}
##RXD and math##
神奇数学题,会发现对于第i个数,若他不是莫比乌斯函数中成0的数,那么他所算出来的值恰好是他自身+后面i * 1 2 {^2} 2+ i * 2 2 {^2} 2 + i * 3 2 {^2} 2 + … + i * ⌊ i ⌋ 2 {\lfloor\sqrt i\rfloor^2} ⌊i⌋2 + … + f(u(i))能由他自身组成比 n k {n^k} nk小的莫比乌斯值为0的数的总数。
所以答案就是 n k {n^k} nk % MOD,快速幂一下即可。n进来的时候记得先MOD一下。
orz没MOD wa了一发被隔壁队超越。
#include <bits/stdc++.h>
#define ll long long
#define MOD 1000000007
#define MAXN 100005
using namespace std;
bool mub[MAXN];
ll ksm(ll a, ll n) {
ll ans = 1, t = a;
while (n) {
if (n & 1) {
ans = (ans * t) % MOD;
}
n >>= 1;
t = (t * t) % MOD;
}
return ans;
}
int main() {
ll n, m, cas = 1;
while (~scanf("%lld %lld", &n, &m)) {
n %= MOD;
printf("Case #%lld: %lld\n", cas++, ksm(n, m % (MOD - 1)));
}
}
RXD’s date##
神奇的签到题,开场半分钟读完,10S码完,吹了1分20S的水看有没有人过题,编译都没编译。。
找小于35的答案即可。orz你们绍兴一中是怕我们被0封所以出了这种签到题嘛
#include <bits/stdc++.h>
using namespace std;
int main() {
int t, c;
while (~scanf("%d", &t)) {
int ans = 0;
for (int i = 0; i < t; i++) {
scanf("%d", &c);
if (c <= 35) {
ans++;
}
}
printf("%d\n", ans);
}
}