计算几何 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. 如何将EXCEL表导入ORACLE数据库中?【转】

    来源:https://zhidao.baidu.com/question/383828330.html?qbl=relate_question_2&word=excel%20%B1%ED%CA ...

  2. 外景VR的应用

    留坑,续写. 最近在做外景的项目,被相关的帧率优化和灯光布置困扰的不要不要的.下面写下我是怎么优化帧率和对帧率的一些理解. 帧率,游戏的重要影响因素,会对玩家的手感以及视觉产生重大的影响,一般的游戏帧 ...

  3. 基于canvas的陈列订货的分析

    订货会软件中又新增了进行陈列订货,即一杆衣服订的显示出来,没订的不显示出来 主要遇到的问题是如何呈现,原先老是想着定位,left,top但是花出来的图容易出现原先的数据填写错误导致后期的图片的呈现出现 ...

  4. Texstudio中文乱码问题

    参考 http://blog.csdn.net/lanbing510/article/details/8723619 1. 用XeLatex编译,这样生成的pdf没有乱码 2.在texstudio中E ...

  5. marquee标签,好神奇啊...

    <html><body><div style="height:190; margin-top:10; margin-bottom:10; width:96%; ...

  6. java 获取文件列表,并按照文件名称排序

    需求:获取全部的日志文件,并按照文件名称倒序排列,把最新的文件放在最前1.获取全部的日志文件:(方法:public List<String> ergodic(File file,List& ...

  7. JS实现图片预加载无需等待

    网站开发时经常需要在某个页面需要实现对大量图片的浏览;用javascript来实现一个图片浏览器,让用户无需等待过长的时间就能看到其他图片 网站开发时经常需要在某个页面需要实现对大量图片的浏览,如果考 ...

  8. js求时间差

    var date1=new Date();  //开始时间 alert("aa"); var date2=new Date();    //结束时间 var date3=date2 ...

  9. hihoCoder 1196 高斯消元·二

    Description 一个黑白网格,点一次会改变这个以及与其连通的其他方格的颜色,求最少点击次数使得所有全部变成黑色. Sol 高斯消元解异或方程组. 先建立一个方程组. \(x_i\) 表示这个点 ...

  10. Count Complete Tree Nodes

    Given a complete binary tree, count the number of nodes. Definition of a complete binary tree from W ...