2012 Multi-University #9
计算几何 A Farmer Greedy
题意:n个点选3个组成三角形,问m个点在三角形内的数字是奇数的这样的三角形个数.
分析:暴力O(N^3*M)竟然能过!我写的搓,加了优化才过掉.正解是先处理出每条线段正下方点的个数,然后枚举每个三角形O(1)计算,cnt[i][j] + cnt[j][k] - cnt[i][k](i,j,k已经对应的点按照x坐标排序),复杂度(n^2*m+n^3).
贴上别人的代码:
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- #include <cstdlib>
- #include <algorithm>
- using namespace std;
- typedef long long ll;
- const int INF = 0x7fffffff;
- const int N = 1000 + 5;
- struct point{
- ll x, y;
- }a[N], b[N];
- int p[N][N];
- bool cmp(point u, point v){
- return u.x < v.x;
- }
- ll cross(point u, point v, point w){
- return (v.x - u.x) * (w.y - u.y) - (v.y - u.y) * (w.x - u.x);
- }
- int main(){
- int n, m;
- int cas = 0;
- while(scanf("%d%d", &n, &m) == 2){
- memset(p, 0, sizeof(p));
- int ans = 0;
- for(int i = 1; i <= n; i ++)scanf("%I64d%I64d", &a[i].x, &a[i].y);
- for(int i = 1; i <= m; i ++)scanf("%I64d%I64d", &b[i].x, &b[i].y);
- sort(a + 1, a + n + 1, cmp);
- for(int i = 1; i <= n; i ++){
- for(int j = i + 1; j <= n; j ++){
- for(int k = 1; k <= m; k ++){
- if(cross(a[i], a[j], b[k]) < 0 && a[i].x < b[k].x && b[k].x < a[j].x)p[i][j] += 1;
- }
- }
- }
- for(int i = 1; i <= n; i ++)
- for(int j = 1; j < i; j ++)p[i][j] = p[j][i];
- for(int i = 1; i <= n; i ++){
- for(int j = i + 1; j <= n; j ++){
- for(int k = j + 1; k <= n; k ++){
- int tmp = p[i][k] - p[i][j] - p[j][k];
- if(tmp < 0)tmp = -tmp;
- if(tmp % 2) ans += 1;
- }
- }
- }
- printf("Case %d: ", ++cas);
- printf("%d\n", ans);
- }
- return 0;
- }
01背包+贪心 B Grid
题意:两个人前后刷墙,问最多能刷多少墙.
分析: 先对位置排序,刷墙最好从最左边刷,那么dp[i]保存了刷到i墙时所需的最小刷墙数,枚举前后点取最小值.
- #include <bits/stdc++.h>
- const int N = 1e3 + 5;
- const int INF = 0x3f3f3f3f;
- std::vector<std::pair<int, int> > A[2];
- int dp[2][N];
- int n, m;
- void solve(int &bv, int &bs) {
- memset (dp, INF, sizeof (dp));
- dp[0][0] = dp[1][0] = 0;
- for (int k=0; k<2; ++k) {
- std::sort (A[k].begin (), A[k].end ());
- for (int i=0; i<A[k].size (); ++i) {
- int pos = A[k][i].first, x = A[k][i].second;
- for (int j=pos; j>=x; --j) {
- dp[k][j] = std::min (dp[k][j], dp[k][j-x] + 1);
- }
- }
- }
- for (int i=0; i<=n; ++i) {
- for (int j=0; j<=n-i; ++j) {
- int tval = i + j;
- int tstep = dp[0][i] + dp[1][j];
- if ((tval > bv && tstep <= m) || (tval == bv && tstep < bs)) {
- bv = tval;
- bs = tstep;
- }
- }
- }
- }
- int main() {
- int T; scanf ("%d", &T);
- for (int cas=1; cas<=T; ++cas) {
- scanf ("%d%d", &n, &m);
- A[0].clear (); A[1].clear ();
- for (int i=0; i<m; ++i) {
- int op, pos, x; scanf ("%d%d%d", &op, &pos, &x);
- if (op == 1) {
- A[0].push_back (std::make_pair (pos, x));
- } else {
- A[1].push_back (std::make_pair (n + 1 - pos, x));
- }
- }
- int bestv = 0, bests = 0;
- solve (bestv, bests);
- printf ("Case %d: %d %d\n", cas, bestv, bests);
- }
- return 0;
- }
树形DP D How to paint a tree
题意:两种操作,1.可以把某棵子树颜色全反转; 2.两个点之间的最短路径上的点颜色反转(可以是同一个点).问最少操作几次能使整棵树颜色相同.
分析:定义状态dp[u][i(0/1)][j(0/1)]表示u结点的子树颜色为i时,是否与父亲节点连接的最小操作数.其中第三维为1表示u与父亲节点连接将要做一次二操作,此时u子树的状态是除u以外的点都与u颜色相反,也就是u点进行二操作后才使得子树颜色相同.
其他类似不写了.
- #include <bits/stdc++.h>
- const int N = 1e4 + 5;
- const int INF = 0x3f3f3f3f;
- int a[N];
- std::vector<int> edge[N];
- int dp[N][2][2];
- int n;
- void _min(int &a, int b) {
- if (a > b) {
- a = b;
- }
- }
- void DFS(int u, int fa) {
- int col = a[u];
- int sum[2] = {0};
- int mn[2][2];
- for (int i=0; i<2; ++i) {
- for (int j=0; j<2; ++j) {
- dp[u][i][j] = INF;
- mn[i][j] = INF;
- }
- }
- int son = 0;
- for (auto v: edge[u]) {
- if (v == fa) {
- continue;
- }
- son++;
- DFS (v, u);
- sum[0] += dp[v][0][0];
- sum[1] += dp[v][1][0];
- int sub = -dp[v][0][0] + dp[v][1][1];
- if (sub <= mn[0][0]) {
- mn[0][1] = mn[0][0];
- mn[0][0] = sub;
- } else if (sub < mn[0][1]) {
- mn[0][1] = sub;
- }
- sub = -dp[v][1][0] + dp[v][0][1];
- if (sub <= mn[1][0]) {
- mn[1][1] = mn[1][0];
- mn[1][0] = sub;
- } else if (sub < mn[1][1]) {
- mn[1][1] = sub;
- }
- }
- if (!son) {
- dp[u][col][0] = 0;
- dp[u][col^1][0] = 1;
- dp[u][col][1] = 0;
- dp[u][col^1][1] = 1;
- } else {
- _min (dp[u][col][0], sum[col]);
- _min (dp[u][col][1], sum[col^1]);
- _min (dp[u][col][1], sum[col^1]+mn[col^1][0]);
- _min (dp[u][col^1][0], sum[col^1]+mn[col^1][0]+mn[col^1][1]+1);
- int tmp[2][2];
- for (int i=0; i<2; ++i) {
- for (int j=0; j<2; ++j) {
- tmp[i][j] = dp[u][i][j];
- }
- }
- for (int i=0; i<2; ++i) {
- _min (dp[u][i][0], tmp[i^1][1] + 1);
- _min (dp[u][i][0], tmp[i][1] + 2);
- _min (dp[u][i][0], tmp[i^1][0] + 1);
- _min (dp[u][i][1], tmp[i^1][1] + 1);
- }
- }
- }
- int solve() {
- DFS (1, 0);
- int ret = std::min (dp[1][0][0], dp[1][1][0]);
- return ret;
- }
- int main() {
- int cas = 0;
- while (scanf ("%d", &n) == 1) {
- for (int i=1; i<=n; ++i) {
- edge[i].clear ();
- }
- for (int u, v, i=1; i<n; ++i) {
- scanf ("%d%d", &u, &v);
- edge[u].push_back (v);
- edge[v].push_back (u);
- }
- for (int i=1; i<=n; ++i) {
- scanf ("%d", a+i);
- }
- printf ("Case %d: %d\n", ++cas, solve ());
- }
- return 0;
- }
状压DP F Moving Bricks
题意:给n个砖头坐标(n<20)和起点,每一次可以从起点出发,抱一块或者两块砖头原路返回,问所走的最短距离以及抱砖的顺序(字典序最小)
分析:明显的状态压缩DP,转移方程:
,
然后想了想直接for循环转移是对的(因为每次比上一个状态最多多了1个),当然BFS也对,不过慢了许多。最后在更新的时候记录从哪些砖头转移过来,从小到大输出(有两块砖顺便输出)。
- #include <bits/stdc++.h>
- const int N = 1 << 20 + 5;
- const int INF = 0x3f3f3f3f;
- int x[21], y[21];
- int dis[21][21];
- int dp[N];
- struct Info {
- int c, id1, id2, nex;
- }pre[N];
- int lk[21];
- bool vis[21];
- int n, S;
- int calc_dis(int i, int j) {
- return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);
- }
- void DP(int s) {
- for (int i=0; i<S; ++i) {
- dp[i] = INF;
- }
- dp[s] = 0;
- //std::queue<int> que; que.push (s);
- //while (!que.empty ()) {
- for (int u=0; u<S; ++u) {
- //int u = que.front (); que.pop ();
- int v;
- for (int i=0; i<n; ++i) {
- if ((u >> i) & 1) {
- continue;
- }
- v = u | (1 << i);
- if (dp[v] > dp[u] + dis[n][i] * 2) {
- dp[v] = dp[u] + dis[n][i] * 2;
- pre[v] = (Info) {1, i, -1, u};
- //que.push (v);
- }
- for (int j=i+1; j<n; ++j) {
- if ((u >> j) & 1) {
- continue;
- }
- v = u | (1 << i) | (1 << j);
- if (dp[v] > dp[u] + dis[n][i] + dis[i][j] + dis[j][n]) {
- dp[v] = dp[u] + dis[n][i] + dis[i][j] + dis[j][n];
- pre[v] = (Info) {2, i, j, u};
- //que.push (v);
- }
- }
- }
- }
- }
- int main() {
- int T; scanf ("%d", &T);
- for (int cas=1; cas<=T; ++cas) {
- int tx, ty;
- scanf ("%d%d", &tx, &ty);
- scanf ("%d", &n);
- for (int i=0; i<n; ++i) {
- scanf ("%d%d", &x[i], &y[i]);
- }
- x[n] = tx; y[n] = ty;
- for (int i=0; i<=n; ++i) {
- for (int j=i; j<=n; ++j) {
- dis[i][j] = dis[j][i] = calc_dis (i, j);
- }
- }
- S = 1 << n;
- int start = 0;
- DP (start);
- int end = S - 1;
- printf ("Case %d:\n%d\n", cas, dp[end]);
- memset (lk, -1, sizeof (lk));
- while (end != start) {
- int a = pre[end].id1, b = pre[end].id2;
- if (b != -1) {
- if (a > b) {
- std::swap (a, b);
- }
- lk[a] = b;
- }
- end = pre[end].nex;
- }
- memset (vis, false, sizeof (vis));
- for (int i=0; i<n; ++i) {
- if (vis[i]) {
- continue;
- }
- vis[i] = true;
- if (i == 0) {
- printf ("1");
- } else {
- printf (" %d", i + 1);
- }
- if (lk[i] != -1 && !vis[lk[i]]) {
- vis[lk[i]] = true;
- printf (" %d", lk[i] + 1);
- }
- }
- puts ("");
- }
- return 0;
- }
数学 G Quadrilateral
题意:求任意四边形面积最大值
分析:可以三分对角线长度.也可以用公式,结论是当四边形的四个顶点都在圆上最大.详细解释
- #include <bits/stdc++.h>
- int a[4];
- double calc(double p) {
- return sqrt ((p-a[0]) * (p-a[1]) * (p-a[2]) * (p-a[3]));
- }
- int main() {
- int n; scanf ("%d", &n);
- for (int cas=1; cas<=n; ++cas) {
- double mx = 0, p = 0;
- for (int j=0; j<4; ++j) {
- scanf ("%d", &a[j]);
- if (mx < a[j]) {
- mx = a[j];
- }
- p += a[j];
- }
- p /= 2;
- printf ("Case %d: ", cas);
- std::sort (a, a+4);
- if (a[0] + a[1] + a[2] <= mx) {
- puts ("-1");
- } else {
- printf ("%.6f\n", calc (p));
- }
- }
- return 0;
- }
博弈 H Stone Game
题意:n长度,左右分别有k个石头,每次白往左,黑往右,移动到最近空的位置,不能移动胜.白先手,问谁必胜.
分析:
k=1时
很容易看出,n为奇数则后手获胜,n为偶数则先手获胜
k>1时
如果n=2*k+1,则棋盘中只有一个空白的格子,每次移动必须移动到当前的空白格子上。先手方可以先随意选择一颗棋子占据中间的位置,然后双方互有移动,移动过程中双方肯定都会选择一颗在己方半场的棋子移动到对方半场里。直到后手方还剩下一颗己方半场的棋子时,先手方把占据中间的棋子移动到对方半场,此时后手方必须移动剩下的这颗棋子到空出的中间的格子里,先手方再把最后一颗棋子移动到新空出的位置即可获胜。
如果n>2*k+1,那么棋盘中就有了多余一个的空白格子。如果n为奇数,先手方只要每次移动己方最靠后的一颗棋子即可获胜。并且第一次移动必须选择1号棋子,否则会让自己的棋子中间留下空白相当于把先手让给了对方,这时对方只要采用先手策略即可获胜;如果n为偶数,那么先手方只需采用n=2*k+1时的策略在双方交会的时候保住先手即可,当然此时的第一步还是1号棋子,否则将失去先手优势。
数位DP J X mod f(x)
题意:问在区间[l, r]范围内满足x % f(x) == 0 (f(x)为所有位数相加的和)的个数.
分析:做掉这题,终于搞明白这一类计数问题用数位DP做.开始我自己推是从低位开始,保存了当前的和以及它%(x*10^i+sum)的信息为下次递推用,但是发现状态信息很难保存,卒~.后来听说有模板,之前写过更恶心的AC自动机+数位DP,那时对记忆化深搜的巧妙方法影响深刻.dp[len][sum][%mod][mod]一维表示长度,一维表示数位和,一维表示对mod取模,该mod是全局,即对所有mod试一次.判断符合的条件就是%mod的值为0,且数位和为mod.
- #include <bits/stdc++.h>
- //len,sum,%MOD,MOD
- int dp[11][82][81][82];
- int digit[10];
- int DFS(int len, int sum, int val, int mod, bool limit) {
- if (len == -1) {
- return val == 0 && sum == mod;
- }
- int &now = dp[len][sum][val][mod];
- if (now != -1 && !limit) {
- return now;
- }
- int ret = 0;
- int d = limit ? digit[len] : 9;
- for (int i=0; i<=d; ++i) {
- ret += DFS (len - 1, sum + i, (val * 10 + i) % mod, mod, limit && i == d);
- }
- if (!limit) {
- now = ret;
- }
- return ret;
- }
- int calc(int x) {
- int p = 0;
- while (x) {
- digit[p++] = x % 10;
- x /= 10;
- }
- int ret = 0;
- for (int i=1; i<=81; ++i) {
- ret += DFS (p - 1, 0, 0, i, true);
- }
- return ret;
- }
- int main() {
- int T; scanf ("%d", &T);
- memset (dp, -1, sizeof (dp));
- for (int cas=1; cas<=T; ++cas) {
- int l, r; scanf ("%d%d", &l, &r);
- printf ("Case %d: %d\n", cas, calc (r) - calc (l-1));
- }
- return 0;
- }
2012 Multi-University #9的更多相关文章
- 针对于网络安全领域中基于PCAP流量的数据集
网络安全领域中基于PCAP流量的数据集 MAWI Working Group Traffic Archive URL:http://mawi.wide.ad.jp/mawi/ CIC dataset ...
- Parallel NetCDF 简介
Parallel NetCDF API 所有C接口前加ncmpi前缀,Fortran接口前加nfmpi前缀 函数返回整数 NetCDF 状态变量 1. Variable and Parameter T ...
- 视觉中的深度学习方法CVPR 2012 Tutorial Deep Learning Methods for Vision
Deep Learning Methods for Vision CVPR 2012 Tutorial 9:00am-5:30pm, Sunday June 17th, Ballroom D (Fu ...
- Google Interview University - 坚持完成这套学习手册,你就可以去 Google 面试了
作者:Glowin链接:https://zhuanlan.zhihu.com/p/22881223来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 原文地址:Google ...
- SQL Server 2012 内存管理 (memory management) 改进
SQL Server 2012 的内存管理和以前的版本相比,有以下的一些变化. 一.内存分配器的变化 SQL Server 2012以前的版本,比如SQL Server 2008 R2等, 有sing ...
- 西安理工大学 李爱民 Xi'an University of Technology, Aimin Li
李爱民-西安理工大学计算机科学与工程学院 ● 简介(Introduction)-> 李爱民(Aimin Li),男,湖北随州人,西安电子科学大学博士(PhD),中共党员.中国计算机学会会员,CS ...
- 微软BI SSRS 2012 Metro UI Win 8 风格的报表课程案例全展示
开篇介绍 微软BI SSRS 2012 Metro UI 高端报表视频教程 (http://www.hellobi.com/course/15)课程从2014年6月开始准备,于2014年9月在 天善B ...
- Online handwriting recognition using multi convolution neural networks
w可以考虑从计算机的“机械性.重复性”特征去设计“低效的”算法. https://www.codeproject.com/articles/523074/webcontrols/ Online han ...
- Patch multi versions of windows via Power shell
Patch multi versions of windows via Power shell $version = Get-WmiObject -Class Win32_OperatingSyste ...
- Weblogic多数据源(Multi Data Sources)应用实践
原创 2012年03月29日 10:55:28 标签: weblogic / 数据库 / 负载均衡 / 数据中心 / jdbc / 应用服务器 大型系统在进行数据库部署时,常常会分为主数据应用中心 ...
随机推荐
- php 实用例子:购物车 涉及session与ajax
login: <div>用户名:<input type="text" id="uid" /></div><div> ...
- Base64原理
一.Base64编码由来 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就 不能通过邮件传送.这样用途就受到了很大的 ...
- html5新增的主体结构元素
1. article 主体结构元素 通常是一篇文章.一个页面.一个独立完整的内容模块一般会带个标题,并放在 header 标签中,article 元素可以互相嵌套,使用频率极高,强调独立性,多注意下 ...
- Druid初步学习
Druid是一个JDBC组件,它包括三部分: DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系. DruidDataSource 高效可管理的数据库连接池 ...
- Asp.net实现直接在浏览器预览Word、Excel、PDF、Txt文件(附源码)
功能说明 输入文件路径,在浏览器输出文件预览信息,经测试极速(Chrome).IE9.Firefox通过 分类文件及代码说明 DemoFiles 存放可测试文件 Default.aspx 启动页 ...
- 清北学堂模拟赛day7 数字碰撞
/* clj:水题别人都满分你不是你就完了,所以说水题一定要细心一点,有这么几个细节:①前导零的处理,全是零的时候要特判②换行要注意,不要多大一行,剩下就是水水的模拟了 */ #include< ...
- 【Alpha版本】 第二天 11.8
一.站立式会议照片: 二.项目燃尽图: 三.项目进展: 成 员 昨天完成任务 今天完成任务 明天要做任务 问题困难 心得体会 胡泽善 我要招聘详情的展示 注册界面的实现 填写招聘时用户填写各个日期到可 ...
- 号外!GNOME 3.22 正式发布喽!!!
导读 经过半年的努力开发,别名为“卡尔斯鲁厄”的 GNOME 3.22 正式发布了!“GNOME Software 可以安装和更新 Flatpak 软件包,GNOME Builder 则可以创建它们, ...
- 坑爹的私有API
iOS私有API扫描工作总结 背景 苹果提供的iOS开发框架分PrivateFramework和Framework,PrivateFramework下的库是绝对不允许在提交的iOS应用中使用的,只允许 ...
- Add Two Numbers LeetCode Java
You are given two linked lists representing two non-negative numbers. The digits are stored in rever ...