计算几何 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的更多相关文章

  1. 针对于网络安全领域中基于PCAP流量的数据集

    网络安全领域中基于PCAP流量的数据集 MAWI Working Group Traffic Archive URL:http://mawi.wide.ad.jp/mawi/ CIC dataset ...

  2. Parallel NetCDF 简介

    Parallel NetCDF API 所有C接口前加ncmpi前缀,Fortran接口前加nfmpi前缀 函数返回整数 NetCDF 状态变量 1. Variable and Parameter T ...

  3. 视觉中的深度学习方法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 ...

  4. Google Interview University - 坚持完成这套学习手册,你就可以去 Google 面试了

    作者:Glowin链接:https://zhuanlan.zhihu.com/p/22881223来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 原文地址:Google ...

  5. SQL Server 2012 内存管理 (memory management) 改进

    SQL Server 2012 的内存管理和以前的版本相比,有以下的一些变化. 一.内存分配器的变化 SQL Server 2012以前的版本,比如SQL Server 2008 R2等, 有sing ...

  6. 西安理工大学 李爱民 Xi'an University of Technology, Aimin Li

    李爱民-西安理工大学计算机科学与工程学院 ● 简介(Introduction)-> 李爱民(Aimin Li),男,湖北随州人,西安电子科学大学博士(PhD),中共党员.中国计算机学会会员,CS ...

  7. 微软BI SSRS 2012 Metro UI Win 8 风格的报表课程案例全展示

    开篇介绍 微软BI SSRS 2012 Metro UI 高端报表视频教程 (http://www.hellobi.com/course/15)课程从2014年6月开始准备,于2014年9月在 天善B ...

  8. Online handwriting recognition using multi convolution neural networks

    w可以考虑从计算机的“机械性.重复性”特征去设计“低效的”算法. https://www.codeproject.com/articles/523074/webcontrols/ Online han ...

  9. Patch multi versions of windows via Power shell

    Patch multi versions of windows via Power shell $version = Get-WmiObject -Class Win32_OperatingSyste ...

  10. Weblogic多数据源(Multi Data Sources)应用实践

    原创 2012年03月29日 10:55:28 标签: weblogic / 数据库 / 负载均衡 / 数据中心 / jdbc / 应用服务器   大型系统在进行数据库部署时,常常会分为主数据应用中心 ...

随机推荐

  1. Solve

    /// <summary> /// Solves this instance. /// </summary> /// <returns>IFeatureClass. ...

  2. thinkphp分页二,分装到funciton.php

    function.php代码 <?php /* 全局分页 * $table 数据表名 * $order 排序 * $pagesize 每页显示N个 * $where 查询条件 * $rollPp ...

  3. 使用Spring和SpringMVC管理bean时要注意的一个小细节

    最近一直在做毕业设计...用到了Shiro和SpringMVC..用过shiro的朋友都知道shiro需要自己去写Realm,然后把Realm注入到SecurityManager中.而Security ...

  4. Protecting against XML Entity Expansion attacks

    https://blogs.msdn.microsoft.com/tomholl/2009/05/21/protecting-against-xml-entity-expansion-attacks/ ...

  5. Bash 会清空从父进程继承来的 OLDPWD

    即便 Bash 没有从父进程继承任何的环境变量,Bash 自己也会创建三个环境变量,分别是: $ env -i bash -c export declare -x OLDPWD declare -x ...

  6. java8入门 错误:找不到或者无法加载主类

    如果你也遇上的这个问题,但是如果你的Java版本不是6以上,这个解决方案可能就不适合你... 最近在跟着李兴华老湿的视频<<编程开发入门Java 8>>的学习Java... 但 ...

  7. JavaScript方法call、apply、caller、callee、bind的使用详解及区别

    一.call 方法 调用一个对象的一个方法,以另一个对象替换当前对象(其实就是更改对象的内部指针,即改变对象的this指向的内容). 即  “某个方法”当做“指定的某个对象”的“方法”被执行. Js代 ...

  8. Mac Pro 软件安装/个性化配置 汇总

    苹果产品维修 一.Spotlight 搜索程序和文档 Spotlight是最最常用的东西, 类似Windows开始菜单中的搜索.  可以用来搜索文档,也可以搜索本机的程序, 这样可以快速启动. 点击右 ...

  9. Java Native Interface 二 JNI中对Java基本类型和引用类型的处理

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...

  10. Form 详细属性--2016年12月4日

    属性       名称 说明   AcceptButton 获取或设置当用户按 Enter 键时所单击的窗体上的按钮.   AccessibilityObject 获取分配给该控件的 Accessib ...