计算几何 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. php常用字符串函数小结

    php内置了98个字符串函数(除了基于正则表达式的函数,正则表达式在此不在讨论范围),能够处理字符串中能遇到的每一个方面内容,本文对常用字符串函数进行简单的小结,主要包含以下8部分:1.确定字符串长度 ...

  2. Python学习笔记——列表

    1.创建列表类型数据并给其赋值 >>> aList = [123,'abc',4.56,['inner','list'],7-9j] >>> aList [123, ...

  3. Linux--niaoge

    鸟哥的Linux私房菜 网络基础: 那 TCP/IP 是如何运作的呢?我们就拿妳常常连上的 Yahoo 入口网站来做个说明好了,整个联机的状态可以这样看: 应用程序阶段:妳打开浏览器,在浏览器上面输入 ...

  4. 关于application/x-www-form-urlencoded等字符编码的解释说明

    在Form元素的语法中,EncType表明提交数据的格式 用 Enctype 属性指定将数据回发到服务器时浏览器使用的编码类型. 下边是说明: application/x-www-form-urlen ...

  5. PHP常用代码汇总

    Get与Post //POST if(isset( $_POST['add_gift'] )) { $game=trim( $_POST['game'] ); } //GET if(isset( $_ ...

  6. nyoj 448 寻找最大数(贪心专题)

    寻找最大数 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 请在整数 n 中删除m个数字, 使得余下的数字按原次序组成的新数最大, 比如当n=920813467185 ...

  7. JAVA中的线程安全与非线程安全

    原文:http://blog.csdn.net/xiao__gui/article/details/8934832 ArrayList和Vector有什么区别?HashMap和HashTable有什么 ...

  8. js自动更新时间+星期

    <div class="top_bar" id="cao" height="28px"><script> setIn ...

  9. ecshop二次开发常用文件位置

    语言包修改: /language/zh_cn/admin/common.php 商品详情页模板: /themes/**/goods.dwt  (最下方有changePrice() 点选属性或改变数量时 ...

  10. WebAPI返回数据类型

    最近开始使用WebAPI,上手很容易,然后有些疑惑 1.WebAPI默认返回什么数据类型,json还是xml? 2.怎么修改WebAPI的返回数据类型,我用IE浏览器请求返回的数据都是JSON格式的, ...