8/13

2016 Multi-University Training Contest 2
官方题解

数学 A Acperience(CYD)
题意:

  给定一个向量,求他减去一个  α(>=0)乘以一个值为任意+1或-1的B向量后得到向量,求这个向量膜的最小值
思路:

  展开式子,当时最小,结果为

代码:

#include <bits/stdc++.h>
using namespace std;long long w,a,b,c,a2;long long gcd(long long x,long long y)
{return y ? gcd(y,x%y) : x;
}int main()
{int T;int n;int i,j,k;scanf("%d",&T);while(T--){scanf("%d",&n);a=0,b=1ll*n,a2=0;for(i=1;i<=n;i++){scanf("%I64d",&w);if(w<0)w=-w;a+=w;a2+=w*w;}a=a*a;c=gcd(a,b);a/=c;b/=c;a=a2*b-a;c=gcd(a,b);a/=c;b/=c;printf("%I64d/%I64d\n",a,b);}return 0;
}

树形DP B Born Slippy(BH)

题意:

  有一棵树,每个节点有权值。对于每一个节点s,使最大,其中v1,v2,...,vm编号的点都是前一个点的祖先(不一定是父亲),opt是位操作。

思路:

  官方给出了一个很巧妙的做法,注意到而且又是位运算,然后因为是树,考虑树形DP。考虑dp[a][b],a表示的数的低8位,b表示数的高8位,dp意思是到当前状态下,下次要和a进行opt以及上一次opt的数是b的最优值。注意理解红字的含义,dp是交替的,对a转移,对b更新。我写的a和b与标程相反也是可以的,因为只要交替就可以,顺序无所。时间复杂度

代码:

#include <bits/stdc++.h>using ll = long long;
using uint = unsigned;const int MOD = 1e9 + 7;
const int N = (1 << 16) + 5;
char op[4];
int n;
int w[N];
std::vector<int> edges[N];uint opt(uint a, uint b) {if (op[0] == 'A') return a & b;if (op[0] == 'O') return a | b;return a ^ b;
}uint dp[1<<8][1<<8];  //dp[低8位][高8位]
uint backup[N][1<<8];
uint ans[N];template<typename T>
T _max(T &a, T b) {if (a == -1 || a < b) a = b;
}void DFS(int u) {uint val = 0;uint a = w[u] & 255, b = w[u] >> 8;for (int i=0; i<256; ++i) {if (dp[i][b] != -1)_max (val, dp[i][b] + opt (i, a));}ans[u] = val + w[u];std::copy (dp[a], dp[a] + 256, backup[u]);for (int i=0; i<256; ++i) {_max (dp[a][i], val + opt (i, b) * 256);}for (int v: edges[u]) {DFS (v);}//back upstd::copy (backup[u], backup[u] + 256, dp[a]);
}uint solve() {memset (dp, -1, sizeof (dp));DFS (1);uint ret = 0;for (int i=1; i<=n; ++i) {ret = (ret + (ll) i * ans[i] % MOD) % MOD;}return ret;
}int main() {int T;scanf ("%d", &T);while (T--) {scanf ("%d%s", &n, op);for (int i=1; i<=n; ++i) {scanf ("%u", w+i);edges[i].clear ();}for (int i=2; i<=n; ++i) {int x;scanf ("%d", &x);edges[x].push_back (i);}printf ("%u\n", solve ());}return 0;
}

不会 C Call It What You Want

归并树 D Differencia(BH)

题意:

  简单来说就是两个数列a和b,两种操作:

  1. 赋值[l, r]区间里a[i]为x

  2. 询问[l, r]区间多少个a[i]>=b[i]

思路:

  看了Claris的代码,强行看懂了。人家的题解写得已经很清楚了,不多说了。这题还有其他的做法,先学会了这一种。前提先知道归并树=归并排序+线段树(《挑战程序设计竞赛》P188),本题的关键是b数组不变,那么考虑第一操作的x对于b数组而言,现在有多少个数字<=x,用线段树维护。

代码:

#include <bits/stdc++.h>const int N = 1e5 + 5;
const int MOD = 1e9 + 7;int A, B;
const int C = ~(1<<31), M = (1<<16)-1;
int rnd(int last) {int a = (36969 + (last >> 3)) * (A & M) + (A >> 16);int b = (18000 + (last >> 3)) * (B & M) + (B >> 16);return (C & ((a << 16) + b)) % 1000000000;
}int dat[20][N], sum[20][2];
int tag[20][2];
int lid[20][N], rid[20][N];
int a[N], b[N];
int ql, qr, x;
int n, m;void upl(int p, int o) {sum[o][0] = p ? p - l + 1 : 0;tag[o][0] = -1;
}void upr(int p, int o) {sum[o][1] = p ? p - l + 1 : 0;tag[o][1] = p;
}void push_up(int o) {sum[o][0] = sum[o][1] = sum[o+1][0] + sum[o+1][1];
}void push_down(int o) {if (tag[o][0]==-1 && tag[o][1]==-1) return ;if (tag[o][0] != -1) upl (lid[tag[o][0]], o+1);if (tag[o][1] != -1) upr (rid[tag[o][1]], o+1);tag[o][0] = tag[o][1] = -1;
}void build(int l, int r, int o) {tag[o][0] = tag[o][1] = -1;if (l == r) {dat[o][l] = b[l];sum[o][0] = sum[o][1] = a[l] >= b[l];return ;}int mid = l + r >> 1;build (l, mid, o+1);build (mid+1, r, o+1);//mergeint lp = l, rp = mid + 1, p = l;while (lp<=mid && rp<=r) {dat[o][p++] = dat[o+1][lp]<dat[o+1][rp] ? dat[o+1][lp++] : dat[o+1][rp++];}while (lp <= mid) dat[o][p++] = dat[o+1][lp++];while (rp <= r) dat[o][p++] = dat[o+1][rp++];//ranklp = l; rp = mid + 1;for (int i=l; i<=r; ++i) {while (lp<=mid && dat[o+1][lp]<=dat[o][i]) lp++;while (rp<=r && dat[o+1][rp]<=dat[i][i]) rp++;lid[o][i] = lp - 1; rid[o][i] = rp - 1;if (lid[o][i] < l) lid[o][i] = 0;if (rid[o][i] <= mid) rid[o][i] = 0;}push_up (o);
}void modify(int p, int l, int r, int o) {if (ql <= l && r <= qr) {}push_down (o);int mid = l + r >> 1, ret = 0;if (ql <= mid) modify (lid[p], l, mid, o+1);if (qr > mid) mofify (rid[p], mid+1, r, o+1);push_up (o);
}int query(int p, int l, int r, int o) {if (ql <= l && r <= qr) {return sum[o][0];}push_down (o);int mid = l + r >> 1, ret = 0;if (ql <= mid) ret += query (l, mid, o+1);if (qr > mid) ret += query (mid+1, r, o+1);return ret;
}void solve() {build (1, n, 1);std::sort (b+1, b+1+n);int last = 0, ans = 0;for (int i=1; i<=m; ++i) {ql = rnd (last) % n + 1; qr = rnd (last) % n + 1; x = rnd (last) + 1;if (ql > qr) std::swap (ql, qr);if ((ql+qr+x) & 1) {int p = std::lower_bound (b+1, b+1+n, x) - b;modify (p, 1, n, 1);} else {int z = query (1, n, 1);ans = (ans + (ll) i * z % MOD) % MOD;last = 0;}}printf ("%d\n", ans);
}int main() {int T;scanf ("%d", &T);while (T--) {scanf ("%d%d%d%d", &n, &m, &A, &B);for (int i=1; i<=n; ++i) scanf ("%d", a+i);for (int i=1; i<=n; ++i) scanf ("%d", b+i);solve ();}return 0;
}

极角排序 E Eureka(BH)

题意:

  xjb推导之后发现就是求多少个子集共线。

思路:

  听说这题用极角排序的要不卡常数,要不卡精度。题解做法是gcd求斜率,因为输入的是整数。计算子集的方法自己看。

代码:

#include <bits/stdc++.h>const double EPS = 1e-10;
double PI = acos (-1.0);struct Point {int x, y;Point() {}Point(int x, int y) : x(x), y(y) {}bool operator < (const Point &rhs) const {return x < rhs.x || (x == rhs.x && y < rhs.y);}Point operator - (const Point &rhs) const {return Point (x-rhs.x, y-rhs.y);}bool operator == (const Point &rhs) const {return x == rhs.x && y == rhs.y;}void reduce() {int g = std::__gcd (abs (x), abs (y));if (g) {x /= g; y /= g;}}void read() {scanf ("%d%d", &x, &y);}
};typedef long long ll;
const int N = 1e3 + 5;
const int MOD = 1e9 + 7;Point p[N], q[N];
int pow_two[N];
int n;void add_mod(int &a, int b) {a += b;if (a >= MOD) a -= MOD;
}void init_pow() {pow_two[0] = 1;for (int i=1; i<N; ++i) {pow_two[i] = (ll) pow_two[i-1] * 2 % MOD;}
}int solve() {std::sort (p, p+n);int ret = 0;for (int i=0; i<n; ++i) {int m = 0, cnt = 0;for (int j=i+1; j<n; ++j) {if (p[i] == p[j]) ++cnt;else q[m++] = p[j] - p[i];}for (int j=0; j<m; ++j) {q[j].reduce ();}std::sort (q, q+m);add_mod (ret, pow_two[cnt] - 1);for (int x=0, y; x<m; x=y) {for (y=x; y<m && q[x] == q[y]; ++y);add_mod (ret, (ll) pow_two[cnt] * (pow_two[y-x]-1) % MOD);}}return ret;
}int main() {init_pow ();int T;scanf ("%d", &T);while (T--) {scanf ("%d", &n);for (int i=0; i<n; ++i) {p[i].read ();}printf ("%d\n", solve ());}return 0;
}

点双连通分量 F Fantasia(BH)

题意:

  有一个无向图G,每个点有权值。定义表示删除点i后的图,表示,其中,意思是删除点i后,每一个连通子图的权值乘积的和。

思路:

  先求点双连通分量,按照题解的做法,根据新点(bcc_cnt)和割顶建成新的图,然后树形DP计算:(v是u子树的点)。显然只有删除割顶时才会多出连通分量,那么先减去全部和,再加回多出来的分量。其他情况:不是割顶而且不是不是根节点,不会多出连通分量,所以只要除掉wi即可。

  官方题解写到还有CDQ+并查集的做法,已经把他去年出的类似的题做掉了,这题待补。

代码:

#include <bits/stdc++.h>typedef long long ll;
const int N = 1e5 + 5;
const int M = 2e5 + 5;
const int MOD = 1e9 + 7;int dfn[N];
int dfs_clock, bcc_cnt;
bool is_cut[N];
std::vector<int> edges[N<<1], bcc[N<<1];
int sta[N];
int top;int w[N<<1], iw[N<<1];
int n, m;int pow_mod(int x, int n) {int ret = 1;for (; n; n>>=1) {if (n & 1) ret = (ll) ret * x % MOD;x = (ll) x * x % MOD;}return ret;
}int Tarjan(int u, int fa) {int lowu = dfn[u] = ++dfs_clock;int child = 0;sta[top++] = u;for (int v: edges[u]) {if (!dfn[v]) {child++;int lowv = Tarjan (v, u);lowu = std::min (lowu, lowv);if (lowv >= dfn[u]) {is_cut[u] = true;bcc[++bcc_cnt].clear ();w[bcc_cnt] = 1;for (; ;) {int x = sta[--top];w[bcc_cnt] = (ll) w[bcc_cnt] * w[x] % MOD;bcc[bcc_cnt].push_back (x);if (x == v) break;}bcc[bcc_cnt].push_back (u);w[bcc_cnt] = (ll) w[bcc_cnt] * w[u] % MOD;}} else if (dfn[v] < dfn[u] && v != fa) {lowu = std::min (lowu, dfn[v]);}}if (fa < 0 && child == 1) is_cut[u] = false;return lowu;
}void find_bcc() {memset (dfn, 0, sizeof (dfn));memset (is_cut, false, sizeof (is_cut));dfs_clock = top = 0; bcc_cnt = n;for (int i=1; i<=n; ++i) {if (!dfn[i]) Tarjan (i, -1);}
}void add_mod(int &a, int b) {a += b;if (a >= MOD) a -= MOD;if (a < 0) a += MOD;
}int fa[N<<1];
int dp[N<<1], sum[N<<1], belong[N<<1];
bool vis[N<<1];void DFS(int u, int pa, int o) {belong[u] = o;fa[u] = pa;vis[u] = true;dp[u] = w[u];for (int v: edges[u]) {if (v == pa) continue;DFS (v, u, o);dp[u] = (ll) dp[u] * dp[v] % MOD;}if (u > n) {for (int v: bcc[u]) {belong[v] = o;vis[v] = true;}}
}int solve() {find_bcc ();for (int i=1; i<=n; ++i) iw[i] = pow_mod (w[i], MOD - 2);for (int i=1; i<=bcc_cnt; ++i) {edges[i].clear ();}for (int i=n+1; i<=bcc_cnt; ++i) {for (int v: bcc[i]) {if (is_cut[v]) {edges[i].push_back (v);edges[v].push_back (i);w[i] = (ll) w[i] * iw[v] % MOD;}}}int sum = 0, ret = 0;memset (vis, false, sizeof (vis));for (int i=n+1; i<=bcc_cnt; ++i) {if (!vis[i]) {DFS (i, -1, i);add_mod (sum, dp[i]);}}for (int i=1; i<=n; ++i) {if (!vis[i]) {DFS (i, -1, i);add_mod (sum, dp[i]);}}for (int i=1; i<=n; ++i) {int x = belong[i];int tmp = sum;add_mod (sum, -dp[x]);if (!is_cut[i]) {if (i != belong[i]) add_mod (sum, (ll) dp[x] * iw[i] % MOD);} else {int tmp2 = (ll) dp[x] * pow_mod (dp[i], MOD - 2) % MOD;if (i != belong[i]) add_mod (sum, tmp2);for (int v: edges[i]) {if (v == fa[i]) continue;add_mod (sum, dp[v]);}}add_mod (ret, (ll) i * sum % MOD);sum = tmp;}return ret;
}int main() {int T;scanf ("%d", &T);while (T--) {scanf ("%d%d", &n, &m);for (int i=1; i<=n; ++i) edges[i].clear ();for (int i=1; i<=n; ++i) {scanf ("%d", w+i);}for (int i=1; i<=m; ++i) {int u, v;scanf ("%d%d", &u, &v);edges[u].push_back (v);edges[v].push_back (u);}printf ("%d\n", solve ());}return 0;
}

不会 G Glorious Brilliance

不懂 H Helter Skelter

hdu 5741 Helter Skelter 官方题解做法的详细证明

贪心 I It's All In The Mind(ZCJ)

题意:

  

思路:

  

代码:

不会 J Join The Future

贪心 K Keep On Movin(BH)

题意:

  有若干个不同的字母,任意组合成若干个回文串,问某种组合使得其中最短的回文串长度最大。

思路:

  好好反思,比赛时紧张,没想好就写,一直WA也是因为没想到奇数的字母也可以分配出来看成偶数字母添加回文串长度,被CYD点醒后立马AC。吸取教训,1. 写代码是一定要想好再写(特别是贪心乱搞题);2. 迟迟不过题,不能三人同时开题,需要交换题目或者合力先争取过某一题。

代码:

#include <bits/stdc++.h>const int INF = 0x3f3f3f3f;
const int N = 1e5 + 5;
int a[N];int main() {int n;int sum[2];int T;scanf ("%d", &T);while (T--) {int ans = INF;scanf ("%d", &n);sum[0] = sum[1] = 0;int m = 0;for (int i=1; i<=n; ++i) {int x;scanf ("%d", &x);if (x & 1) {ans = std::min (ans, x);a[m++] = x;} else {sum[0] += x;}}if (m == 0) {ans = sum[0];printf ("%d\n", ans);continue;}std::sort (a, a+m);int mn = a[0];for (int i=1; i<m; ++i) {int tmp = a[i] - mn;a[i] = mn;sum[0] += tmp;}sum[0] /= 2;ans = mn + sum[0] / m * 2;printf ("%d\n", ans);}return 0;
}

DP+bitset L La Vie en rose(BH)

题意:

  

思路:

  数据加强了,时限缩短一半,暴力很难跑过去了。标程都T了,好在铭神常数小,跑得快~。明天早上再看看

代码:

#include <bits/stdc++.h>
using LL = long long ;
#define ALL(v) (v).begin(),(v).end()
#define showtime printf("time = %.15f\n",clock() / (double)CLOCKS_PER_SEC)const int N = 100000 + 5;
const int M = 5000 + 5;
int n,m;
char s[N],t[M];std::bitset<N> bs[3],w[26];void work() {for (int i = 0; i < 3; ++ i) {bs[i].reset();}for (int i = 0; i < 26; ++ i) {w[i].reset();}for (int i = 0; i < n; ++ i) {w[s[i] - 'a'][i] = 1;}for (int i = 0; i < n; ++ i) {bs[0][i] = 1;}for (int i = 0; i < m; ++ i) {int a = t[i] - 'a';bs[(i + 1) % 3] = bs[i % 3] & w[a] >> i;if (i > 0) {int b = t[i - 1] - 'a';bs[(i + 1) % 3] |= bs[(i + 2) % 3] & w[a] >> i - 1 & w[b] >> i;}}for (int i = 0; i < n; ++ i) {if (bs[m % 3][i] == 1) putchar('1');else putchar('0');}puts("");
}int main() {int cas;scanf("%d",&cas);while (cas--) {scanf("%d%d",&n,&m);scanf("%s%s",s,t);work();}
}

不会 M Memento Mori

转载于:https://www.cnblogs.com/NEVERSTOPAC/p/5692901.html

2016 Multi-University Training Contest 2相关推荐

  1. 2016 Multi-University Training Contest 10

    solved 7/11 2016 Multi-University Training Contest 10 题解链接 分类讨论 1001 Median(BH) 题意: 有长度为n排好序的序列,给两段子 ...

  2. Sichuan University Programming Contest 2018 Preliminary

    嗯为了防止大家AK,所以这次的A题和K题我们就当做不存在好了! 经历了昨天写了两个多小时的博客没保存的心态炸裂,今天终于下了个Markdown.所以我猜这篇的格式应该会更好看一点! 好吧废话不多说 题 ...

  3. HDU 6091 - Rikka with Match | 2017 Multi-University Training Contest 5

    思路来自 某FXXL 不过复杂度咋算的.. /* HDU 6091 - Rikka with Match [ 树形DP ] | 2017 Multi-University Training Conte ...

  4. HDU 6051 - If the starlight never fade | 2017 Multi-University Training Contest 2

    /* HDU 6051 - If the starlight never fade [ 原根,欧拉函数 ] | 2017 Multi-University Training Contest 2 题意: ...

  5. HDU 6058 - Kanade's sum | 2017 Multi-University Training Contest 3

    /* HDU 6058 - Kanade's sum [ 思维,链表 ] | 2017 Multi-University Training Contest 3 题意:给出排列 a[N],求所有区间的第 ...

  6. 2017 Multi-University Training Contest - Team 3 Kanade's sum hd6058

    地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=6058 题目: Kanade's sum Time Limit: 4000/2000 MS (J ...

  7. 2018 Multi-University Training Contest 3 Problem F. Grab The Tree 【YY+BFS】

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6324 Problem F. Grab The Tree Time Limit: 2000/1000 MS ...

  8. hdu 4925 Apple Tree--2014 Multi-University Training Contest 6

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4925 Apple Tree Time Limit: 2000/1000 MS (Java/Others ...

  9. HUST-2015 Multi-University Training Contest 9

    2015 Multi-University Training Contest 9 solutions BY xudyh 1001.Expression 记dp_{l,r}dp​l,r​​表示l,rl, ...

  10. 2016 China Collegiate Programming Contest Final

    2016 China Collegiate Programming Contest Final Table of Contents 2016 China Collegiate Programming ...

最新文章

  1. Ubuntu 使用国内apt源
  2. 2022年预训练的下一步是什么?
  3. 计算4位数每位数相加之和(Python)
  4. 用键盘怎么直接打出小于等于和大于等于
  5. 多元线性回归分析matlab实验报告,利用MATLAB进行多元线性回归.ppt
  6. 好程序员web前端分享详细了解JavaScript函数
  7. 日语学习-多邻国-人
  8. 在Linux 安装Python3.5.6详细文档!!!!
  9. ScreenRecord(about C# winform)
  10. OKR案例——不同类型的OKR实例
  11. Add Juniper SRX Cluster into JunOS Space 16.1 Security Director
  12. vivado SRIO 学习
  13. Kconfig使用详解
  14. 电商api全境,Python网络爬虫与数据采集
  15. 华为照片在哪个文件夹_华为手机相册照片在哪个文件夹(这2个方法帮你轻松找到)...
  16. 苏宁数据中台架构实践
  17. 浅谈SAP顾问未来十年在中国的发展前景
  18. 一次性听懂英语影视节目的真实经历和经验谈
  19. 【python数据类型】
  20. 北大计算机图灵班,北京大学举办图灵班开班仪式

热门文章

  1. Aurora-------在 MSOffice 内输入 LaTeX 公式的很好用插件
  2. windows server 2012 --安装远程桌面服务后无法远程的问题
  3. tomcat启动报错 关键字:java.lang.NoClassDefFoundError和 java.lang.ClassNotFoundExceeption
  4. linux-推荐两款好用的录屏软件
  5. nyoj-78-圈水池(Graham算法求凸包)
  6. 5-8 第五天 微信 JS-SDK
  7. 2016.10.26
  8. Web负载均衡与分布式架构
  9. React基础----ReactJS的使用(一)
  10. js获取谷歌浏览器版本