计算几何 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. <<< eclipse软件部署修改项目的访问地址

    在eclipse开发javaweb项目的时候,访问项目时需要在浏览器地址输入:localhost:8080/项目名  但是大多数部署到服务器的时候访问的是根目录,就是不加localhost:8080后 ...

  2. iOS plist文件创建

    iOS中plist的创建,数据写入与读取功能创建一个test.plist文件,textInput作为输入,displayLabel作为显示,有一个按钮来触发保持程序triggerStorage: -( ...

  3. 牛顿法|阻尼牛顿法|拟牛顿法|DFP算法|BFGS算法|L-BFGS算法

    一直记不住这些算法的推导,所以打算详细点写到博客中以后不记得就翻阅自己的笔记. 泰勒展开式 最初的泰勒展开式,若  在包含  的某开区间(a,b)内具有直到n+1阶的导数,则当x∈(a,b)时,有: ...

  4. XML编码utf-8有中文无法解析或乱码 C#

    XML的encoding="UTF-8" ,含有中文的话(部分)会出现乱码. 网上还是很多这类问题跟解决办法的. 表现为用ie或者infopath之类的xml软件打不开这个xml, ...

  5. ASP.NET WEB API路由机制

    (一)路由原理 (二)路由设计架构分析 RouteBase

  6. Tomcat SSL的安装及配置中遇到问题

    配置tomcat服务器利用SSL进行加密. 一.生成密钥库 具体生成方式就不讲了,tomcat支持的keystore的格式有JKS,PKCS11和PKCS12 JKS是jdk /bin目录下keyto ...

  7. [Search Engine] 搜索引擎技术之网络爬虫

    随着互联网的大力发展,互联网称为信息的主要载体,而如何在互联网中搜集信息是互联网领域面临的一大挑战.网络爬虫技术是什么?其实网络爬虫技术就是指的网络数据的抓取,因为在网络中抓取数据是具有关联性的抓取, ...

  8. Linux网络下载命令 wget 简介

    wget 是一个命令行的下载工具.对于我们这些 Linux 用户来说,几乎每天都在使用它.下面为大家介绍几个有用的 wget 小技巧,可以让你更加高效而灵活的使用 wget. $ wget -r -n ...

  9. jquery解析php通过ajax传过来的json二维数组对象

    ajax获得php传过来的json二维数组对象,jquery解析 php代码: <?php $news = array( '武汉'=>array(1,2,3), '广州'=>arra ...

  10. .net 根据银行卡获取银行信息

    using System; using System.Collections.Generic; using System.Linq; using System.Web; /// <summary ...