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 / 应用服务器 大型系统在进行数据库部署时,常常会分为主数据应用中心 ...
随机推荐
- pair correlation ggpair ggmatrix
https://zhuanlan.zhihu.com/p/23400450 首发于 R语言数据分析与可视化 关注专栏 登录 写文章 R 语言矩阵散点图 EasyCharts· 15 天前 散点 ...
- lodop打印控件
http://www.c-lodop.com/demolist/PrintSampIndex.html
- css面包屑导航编号
content:counter(flag);counter-increment: flag;-->一般给导航条编号1,2,3
- Bootstrap学习------按钮
Bootstrap为我们提供了按钮组的样式,博主写了几个简单的例子,以后也许用的到. 效果如下 代码如下 <!DOCTYPE html> <html> <head> ...
- Daily Build
Daily Build 是一件非常有意义的事情,也是敏捷开发中关于 “持续集成” 的一个实践.Daily Build 对于开发来说有如下好处: 保证了每次 check in 的代码可用,不会造成整个工 ...
- URL详解
浏览器因特网资源:URL是浏览器寻找信息时所需的资源位置,通过URL,应用程序才能找到并使用共享因特网上大量的数据资源. 大部分URL都遵循一种标准的格式: ①HTTP协议(http://或者http ...
- spark安装(实战)
sparksql+hive :http://lxw1234.com/archives/2015/06/294.htm 1,安装scala http://scala-lang.org/download/ ...
- 简单的方向传感器SimpleOrientationSensor
SimpleOrientationSensor是一个简单的方向传感器.能够识别手机如下表的6种方向信息: SimpleOrientation枚举变量 方向 NotRotated 设备未旋转 Rotat ...
- [Machine Learning & Algorithm] 随机森林(Random Forest)
1 什么是随机森林? 作为新兴起的.高度灵活的一种机器学习算法,随机森林(Random Forest,简称RF)拥有广泛的应用前景,从市场营销到医疗保健保险,既可以用来做市场营销模拟的建模,统计客户来 ...
- UI第十二节
- (void)viewDidLoad { [super viewDidLoad]; UIButton *btn = [UIButton buttonWithType:UIButt ...