训练地址

A:

树剖板子题

求最小值的时候要注意值是不是有负数,如果有,初值要置为$-INF$

 #include <bits/stdc++.h>
using namespace std; #define N 30010
#define INF 0x3f3f3f3f
int n, q, arr[N];
vector <int> G[N]; int fa[N], deep[N], sze[N], son[N], top[N], p[N], fp[N], cnt;
void DFS(int u)
{
sze[u] = ;
for (auto v : G[u]) if (v != fa[u])
{
fa[v] = u;
deep[v] = deep[u] + ;
DFS(v);
sze[u] += sze[v];
if (!son[u] || sze[v] > sze[son[u]]) son[u] = v;
}
} void getpos(int u, int sp)
{
top[u] = sp;
p[u] = ++cnt;
fp[cnt] = u;
if (!son[u]) return;
getpos(son[u], sp);
for (auto v : G[u]) if (v != fa[u] && v != son[u])
getpos(v, v);
} namespace SEG
{
struct node
{
int Max, sum;
node () {}
node (int Max, int sum) : Max(Max), sum(sum) {}
node operator + (const node &other) const { return node(max(Max, other.Max), sum + other.sum); }
}a[N << ], res;
void build(int id, int l, int r)
{
if (l == r)
{
a[id] = node(arr[fp[l]], arr[fp[l]]);
return;
}
int mid = (l + r) >> ;
build(id << , l, mid);
build(id << | , mid + , r);
a[id] = a[id << ] + a[id << | ];
}
void update(int id, int l, int r, int pos, int val)
{
if (l == r)
{
a[id] = node(val, val);
return;
}
int mid = (l + r) >> ;
if (pos <= mid) update(id << , l, mid, pos, val);
else update(id << | , mid + , r, pos, val);
a[id] = a[id << ] + a[id << | ];
}
void query(int id, int l, int r, int ql, int qr)
{
if (l >= ql && r <= qr)
{
res = res + a[id];
return;
}
int mid = (l + r) >> ;
if (ql <= mid) query(id << , l, mid, ql, qr);
if (qr > mid) query(id << | , mid + , r, ql, qr);
}
} void query(int u, int v)
{
while (top[u] != top[v])
{
if (deep[top[u]] < deep[top[v]]) swap(u, v);
SEG::query(, , n, p[top[u]], p[u]);
u = fa[top[u]];
}
if (deep[u] > deep[v]) swap(u, v);
SEG::query(, , n, p[u], p[v]);
} int main()
{
while (scanf("%d%d", &n, &q) != EOF)
{
cnt = ;
memset(son, , sizeof son);
for (int i = ; i <= n; ++i) scanf("%d", arr + i), G[i].clear();
for (int i = , u, v; i < n; ++i)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
DFS(); getpos(, ); SEG::build(, , n);
for (int i = , op, x, y; i <= q; ++i)
{
scanf("%d%d%d", &op, &x, &y);
if (op == ) SEG::update(, , n, p[x], y);
else
{
SEG::res = SEG::node(-INF, );
query(x, y);
printf("%d\n", op == ? SEG::res.Max : SEG::res.sum);
}
}
}
return ;
}

B:

$b^2 = 2 \cdot a \cdot (a + 1) ^ 2$

$b = \sqrt{2 \cdot a} \cdot (a +1)$

所以a一定是个平方数的两倍

即$a = 2 \cdot i^2 $

枚举出答案,再二分查找

 #include <bits/stdc++.h>
using namespace std; #define ull unsigned long long
#define N 6000020
ull res[N]; int main()
{
for (int i = ; i < N; ++i)
res[i] = (ull) * i * ((ull) * i * i + );
//cout << res[N - 1] << endl;
int t; cin >> t;
while (t--)
{
ull n; scanf("%llu", &n);
int pos = lower_bound(res, res + N, n) - res;
printf("%llu\n", res[pos]);
}
return ;
}

C:

$倒着推过来$

$对于'u' 记录一下最近的位置$

$对于'm',记录一下离他最近的'u'的位置$

$对于'c' , 记录一下离(离他最近的'm'的)最近的'z'的位置$

$对于'z',可以直接求答案$

 #include <bits/stdc++.h>
using namespace std; #define N 100010
#define INF 0x3f3f3f3f
char s[N];
int f[]; int main()
{
while (scanf("%s", s + ) != EOF)
{
memset(f, INF, sizeof f);
for (int i = strlen(s + ); i >= ; --i)
{
if (s[i] == 'u') f[] = i;
else if (s[i] == 'm')
{
if (f[] != INF)
f[] = min(f[], f[] - );
}
else if (s[i] == 'c')
{
if (f[] != INF)
f[] = min(f[], f[] - );
}
else if (s[i] == 'z')
{
if (f[] != INF)
f[] = min(f[], f[] - i - );
}
}
printf("%d\n", f[] == INF ? - : f[]);
}
return ;
}

D:

贪心

考虑所有物品都要放进去

那么肯定先放$a_i <= b_i的物品,因为这些物品放进去背包会扩容$

那么放这些物品的时候按照$a_i从小到大的顺序排放$

$因为如果小的都放不下,那么大的肯定放不下,但是大的可以等小的放进去扩容之后可能就可以放下$

那么剩下的物品按照$(a_i - b_i)从小到大的顺序排放$

$因为我们要放一件物品要尽量使得背包缩小的体积较小,这样对后面物品的影响也较小$

 #include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 100010
int t, n; ll v;
struct node
{
int a, b;
node () {}
node (int a, int b) : a(a), b(b) {}
};
vector <node> p, q; bool ok()
{
for (auto it : p)
{
if (v < it.a) return false;
v += it.b - it.a;
}
for (auto it : q)
{
if (v < it.a) return false;
v += it.b - it.a;
}
return true;
} int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%d%lld", &n, &v);
p.clear(), q.clear();
for (int i = , a, b; i <= n; ++i)
{
scanf("%d%d", &a, &b);
if (a <= b) p.emplace_back(a, b);
else q.emplace_back(a, b);
}
sort(p.begin(), p.end(), [](node x, node y) { return x.a < y.a; });
sort(q.begin(), q.end(), [](node x, node y) { return x.a - x.b > y.a - y.b; });
puts(ok() ? "yes" : "no");
}
return ;
}

E:

签到。

 #include <bits/stdc++.h>
using namespace std; #define ll long long
int t;
ll n, k; int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%lld%lld", &n, &k);
printf("%lld\n", k);
}
return ;
}

F:

题意:

给出一个循环节,求这个循环节上的哪些位置,使得从这个位置出发

不论到达哪个位置,前缀1的个数都大于前缀0的个数

思路:

刚开始的想法是线段树的$O(nlogn)做法$

维护处前缀0的个数和前缀1的个数,然后枚举起始位置,两个起始位置之间$O(logn)转移,T了$

然后又考虑了单调队列的做法,$维护一个lazy, O(n),过了$

最后看了看别人的代码,答案是$1的个数-0的个数,晕了$

感觉,首先复杂度没有算法,很明显的需要线性做法,却要硬刚带$log的$

再考虑一下,答案为什么是$1的个数-0的个数$

首先,所有0所处的位置都不可能作为起始位置

再考虑,有哪些1是不可以的

我们考虑连续的0,如果有一段连续的$x个0,那么这x个0往前数x个1,这x个1都是不可以的$

因为肯定至少存在一个位置不满足要求

$再考虑离散的0,那么离散的0直接理解为连续的1个0即可$

 #include <bits/stdc++.h>
using namespace std; #define N 200010
int t, n, a[N], sum[N], dq[N]; int main()
{
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (int i = ; i <= n; ++i)
{
scanf("%d", a + i);
a[i + n] = a[i];
}
int l = , r = ;
for (int i = , tmp = ; i <= n; ++i)
{
tmp += a[i];
sum[i] = * tmp - i;
while (l <= r && sum[dq[r]] > sum[i]) --r;
dq[++r] = i;
}
int res = , lazy = ;
for (int i = ; i <= n; ++i)
{
while (l <= r && dq[l] < i) ++l;
if (sum[dq[l]] + lazy > ) ++res;
sum[i + n] = sum[i + n - ] + * (a[i + n] ? : -);
while (l <= r && sum[dq[r]] > sum[i + n]) --r;
lazy += * (a[i] ? - : );
dq[++r] = i + n;
}
printf("%d\n", res);
}
return ;
}

G:

签到。

 #include <bits/stdc++.h>
using namespace std; int main()
{
int t; cin >> t;
while (t--)
{
long long n, m;
scanf("%lld%lld", &n, &m);
printf("%lld\n", m - n);
}
return ;
}

H:

题意:

将一个n * n矩形分成两个相同的部分,求方案数

思路:

n 为奇数 答案为0

然后从中间开始搜,对称标记

 #include <bits/stdc++.h>
using namespace std; int t, ans[], res, n;
int used[][];
int Move[][] =
{
, -,
, ,
, ,
-, ,
}; void DFS(int x, int y)
{
if (x == || y == || x == n || y == n)
{
++res;
return;
}
for (int i = ; i < ; ++i)
{
int nx = x + Move[i][];
int ny = y + Move[i][];
if (used[nx][ny] == )
{
used[nx][ny] = ;
used[n - nx][n - ny] = ;
DFS(nx, ny);
used[nx][ny] = ;
used[n - nx][n - ny] = ;
}
}
} int main()
{
for (int i = ; i < ; ++i)
{
if (i & ) ans[i] = ;
else
{
memset(used, , sizeof used);
res = ; n = i;
used[i / ][i / ] = ;
DFS(i / , i / );
ans[i] = res / ;
}
}
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
printf("%d\n", ans[n]);
}
return ;
}

I:

按题意模拟即可。

 #include <bits/stdc++.h>
using namespace std; #define N 10010
int t, n;
string str;
string var[N], save[N];
int Size[N], Len[N];
map <string, int> mp; void getName(int i, int len)
{
string name = "";
for (; i < len; ++i)
{
if (str[i] == '[')
{
++i;
break;
}
name += str[i];
}
int big = ;
for (; i < len; ++i)
{
if (str[i] == ']') break;
big = big * + str[i] - '';
}
++n;
mp[name] = n;
var[n] = name;
save[n] = "";
Size[n] = big;
Len[n] = ;
} int main()
{
ios::sync_with_stdio(false);
cin.tie(); cout.tie();
cin >> t; getline(cin, str);
while (t--)
{
n = ;
mp.clear();
while ()
{
getline(cin, str);
if (str == "return 0;") break;
if (str[] == 'c' && str[] == 'h')
{
for (int i = , len = str.size(); i < len; ++i) if (str[i] == ' ')
getName(i + , len);
}
else if (str[] == 'g')
{
string name = "";
str += "\n";
int i = , len = str.size();
for (; i < len; ++i) if (str[i] == ' ')
{
++i;
break;
}
for (; i < len; ++i)
{
if (str[i] == ' ')
{
++i;
break;
}
name += str[i];
}
int id = mp[name];
Len[id] = len - i;
string s = "";
for (int j = ; i < len && j < Size[id]; ++i, ++j)
s += str[i];
save[id] = s;
}
else
{
string name = "";
int i = , len = str.size();
for (; i < len; ++i) if (str[i] == ' ')
{
++i;
break;
}
for (; i < len; ++i) name += str[i];
int id = mp[name];
string res = save[id];
int remind = Len[id] - Size[id];
for (int i = id + ; remind > && i <= n; ++i)
{
res += save[i];
remind -= Size[i] - Len[i];
}
if (res.end()[-] != '\n') res += "\n";
cout << res;
}
}
}
return ;
}

j:

考虑如果没有$gcd(x, y) != 1 的限制$

那么直接处理处b[a[i]]

再对于$a[b[i]] 直接求答案$

有这个限制我们可以考虑容斥,可以直接用莫比乌斯函数来容斥

 #include <bits/stdc++.h>
using namespace std; #define ll long long
#define N 100010
int n;
int a[N], b[N];
bool check[N]; int mu[N], prime[N];
void Moblus()
{
memset(check, false, sizeof check);
mu[] = ;
int tot = ;
for (int i = ; i < N; ++i)
{
if (!check[i])
{
prime[++tot] = i;
mu[i] = -;
}
for (int j = ; j <= tot; ++j)
{
if (i * prime[j] >= N) break;
check[i * prime[j]] = true;
if (i % prime[j] == )
{
mu[i * prime[j]] = ;
break;
}
else
{
mu[i * prime[j]] = -mu[i];
}
}
}
} ll vis[N];
ll f(int t)
{
ll res = ;
for (int i = t; i <= n; i += t) ++vis[b[a[i]]];
for (int i = t; i <= n; i += t) res += vis[a[b[i]]];
for (int i = t; i <= n; i += t) --vis[b[a[i]]];
return res;
} int main()
{
Moblus();
while (scanf("%d", &n) != EOF)
{
memset(vis, , sizeof vis);
for (int i = ; i <= n; ++i) scanf("%d", a + i);
for (int i = ; i <= n; ++i) scanf("%d", b + i);
ll res = ;
for (int i = ; i <= n; ++i)
res += mu[i] * f(i);
printf("%lld\n", res);
}
return ;
}

2017年浙江中医药大学程序设计竞赛 Solution的更多相关文章

  1. 2018年浙江中医药大学程序设计竞赛 Solution

    Problem A. Jhadgre的C语言程序 签. #include <bits/stdc++.h> using namespace std; int main() { puts(&q ...

  2. 2017年浙江理工大学程序设计竞赛校赛 题解&源码(A.水, D. 简单贪心 ,E.数论,I 暴力)

    Problem A: 回文 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 1719  Solved: 528 Description 小王想知道一个字 ...

  3. 2017年浙江中医药大学大学生程序设计竞赛(重现赛)D - CC的神奇背包

    题目描述 cc最近收到了好多礼物,对着满地大小不一的礼物,她想要一个包来装,于是dd就掏出了一个会说话的神奇背包给cc装礼物.cc为了一次性装尽可能多的礼物,于是跟这个背包定下了一个规则,对每个礼物, ...

  4. 2017年中国大学生程序设计竞赛-中南地区赛暨第八届湘潭市大学生计算机程序设计大赛题解&源码(A.高斯消元,D,模拟,E,前缀和,F,LCS,H,Prim算法,I,胡搞,J,树状数组)

    A------------------------------------------------------------------------------------ 题目链接:http://20 ...

  5. 2018年浙江理工大学程序设计竞赛校赛 Problem I: 沙僧

    沙僧 思路: dfs序+差分数组 分层考虑,通过dfs序来查找修改的区间段,然后用差分数组修改 代码: #include<bits/stdc++.h> using namespace st ...

  6. 华东交通大学2017年ACM“双基”程序设计竞赛 1009

    Problem Description MDD随机生成了n(n<le5)个随机数x(x<=1e9),这n个随机数排成一个序列,MDD有q(q<=le5)个询问,每个询问给你一个a,问 ...

  7. 华东交通大学2017年ACM“双基”程序设计竞赛 1005

    Problem Description 假设你有一个矩阵,有这样的运算A^(n+1) = A^(n)*A (*代表矩阵乘法)现在已知一个n*n矩阵A,S = A+A^2+A^3+...+A^k,输出S ...

  8. 华东交通大学2017年ACM“双基”程序设计竞赛 1003

    Problem Description 有两个球在长度为L的直线跑道上运动,两端为墙.0时刻小球a以1m/s的速度从起点向终点运动,t时刻小球b以相同的速度从终点向起点运动.问T时刻两球的距离.这里小 ...

  9. 华东交通大学2017年ACM“双基”程序设计竞赛 1002

    Problem Description 一天YZW参加了学校组织交际舞活动,活动的开始活动方分别给男生和女生从1-n进行编号,按照从小到大顺时针的方式进行男女搭档分配,相同编号的男女组合成一对,例如一 ...

随机推荐

  1. docker tag 详解

    docker tag 用于给镜像打标签,语法如下: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] ① 比如我现在有一个 centos 镜像: [ro ...

  2. Android中的动画,选择器,样式和主题的使用

    一.动画: 1.动画的分类: 1).Tween动画:这种实现方式可以使视图组件移动.放大.缩小以及产生透明度的变化: 2).Frame动画:传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影. ...

  3. AsycnTask

    一.异步任务加载网络数据: 在Android中提供了一个异步任务的类AsyncTask,简单来说,这个类中的任务是运行在后台线程中的,并可以将结果放到UI线程中进行处理,它定义了三种泛型,分别是Par ...

  4. linux系统socket通信编程1

    Linux下的Socket编程大体上包括Tcp Socket.Udp Socket即Raw Socket这三种,其中TCP和UDP方式的Socket编程用于编写应用层的socket程序,是我们用得比较 ...

  5. vue2.0+element-ui(01简单点的单页面)

    前言: 在<Vue.js权威指南>刚出版的时候,自己就作为一名前端粉捧了一把场,可是真是应了那句“出来混,总是要还的“这句话了,那时候信心满满的买来书想要认真研究,最终却还是把它搁浅了.直 ...

  6. C#正则表达式提取HTML中IMG标签中的SRC地址

    百度到的一个,这里就直接贴了 http://blog.csdn.net/smeller/article/details/7108502#comments 一般来说一个 HTML 文档有很多标签,比如“ ...

  7. <转>KMP算法详解

    看了好久的KMP算法,都一直没有看明白,直到看到了这篇博客http://www.tuicool.com/articles/e2Qbyyf让我瞬间顿悟. 如果你看不懂 KMP 算法,那就看一看这篇文章 ...

  8. Linux进程数据结构详解

    1.Linux的进程简介: 支持多线程的操作系统中,进程是资源分配的最小单位,线程是调度的基本单位.Linux是现代的32位或64位的支持多线程的操作系统,不过Linux是一种以轻量级进程作为线程,多 ...

  9. maven setting详细解读

    全局配置: ${M2_HOME}/conf/settings.xml 用户配置: ${user.home}/.m2/settings.xml note:用户配置优先于全局配置.${user.home} ...

  10. ShowDoc 搭建 (未成功....)

    官方教程:https://www.showdoc.cc/help?page_id=13732 下载了showdoc,服务器映射本地磁盘的时候,服务器用户名和密码忘了... 远程服务器用户名和密码修改 ...