2016年NK冬季训练赛 民间题解
A题 水题,考察对行的读入和处理,注意使用long long
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main()
{
char ch;
long long a, sum=, Min;
char S[];
while(cin.getline(S, ))
{
Min = 1e9; a = ;
for(int i = ; i < strlen(S); i++)
{
if(S[i] == ' ')
{
Min = min(Min, a);
a = ;
} else
a = a* + S[i] - '';
}
if(a != ) Min = min(Min, a);
sum += Min;
}
cout<<sum<<endl;
}
B题 贪心算法,先排序,然后依次兑换即可,注意使用long long
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
struct T
{
int x, y;
bool operator <(const T &B) const
{ return y < B.y; }
}a[];
int main()
{
long long n, k;
while(cin>>n>>k)
{
for(int i = ; i < n; i++) cin>>a[i].x>>a[i].y;
sort(a, a+n);
int ans = -;
for(int i = ; i < n; i++)
{
if(k < a[i].y) break;
k += a[i].x;
ans = i;
}
cout<<ans+<<endl;
}
}
C题 可以用dp做,如果把dp的转移方程变成一个矩阵,那么这个矩阵恰好就是这个图的邻接矩阵,然后只要求它的k次幂即可,注意存在自环和重边的情况
这里可以利用矩阵乘法的一个优化,可以把常数优化很多。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <iomanip>
using namespace std;
const int mod = ;
const int maxn = ;
int n,m;
struct Matrix
{
long long v[maxn][maxn];
int n;
Matrix() { memset(v, , sizeof(v));}
Matrix operator *(const Matrix &B)
{
Matrix C; C.n = n;
for(int i = ; i < n; i++)
for(int j = ; j < n; j++)
{
if(v[i][j] == ) continue;
for(int k = ; k < n; k++)
C.v[i][k] = (C.v[i][k] + v[i][j]*B.v[j][k])%mod;
}
return C;
}
}A, B;
Matrix power(Matrix A, int k)
{
Matrix ans;
ans.n = n;
for(int i = ; i < n; i++) ans.v[i][i] = ;
while(k)
{
if(k&) ans = ans*A;
A = A*A; k >>= ;
}
return ans;
}
int a, b, k, t;
int main()
{
while(cin>>n>>m>>k>>t)
{
A.n = n;
for(int i = ; i <= m; i++)
{
scanf("%d %d", &a, &b);
A.v[a-][b-]++;
if(a != b) A.v[b-][a-]++;
}
B = power(A, k);
while(t--)
{
scanf("%d %d", &a, &b);
printf("%d\n", B.v[a-][b-]);
}
}
return ;
}
D题 建图后直接floyed即可,在树上的边权是距离除以速度v,然后再枚举出在同一x坐标的两个点,边权为自由落体的时间。(这里代码有个bug,更新边权要用min的方法更新)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
double eps = 1e-;
double d[][];
struct point
{
double x, y;
}p[];
int n, v, f;
double dis(point &A, point &B)
{ return sqrt((A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y)); }
int main()
{
while(cin>>n>>v)
{
for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
d[i][j] = 1e8;
for(int i = ; i <= n; i++)
{
cin>>p[i].x>>p[i].y>>f;
if(f == ) continue;
d[i][f] = dis(p[i], p[f])/v;
d[f][i] = d[i][f];
}
for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
{
if(i == j) continue;
if(p[i].x == p[j].x && (p[i].y - p[j].y > eps))
d[i][j] = sqrt((p[i].y - p[j].y)*/10.0);
}
for(int k = ; k <= n; k++)
for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
if(d[i][j] - d[i][k] - d[k][j] > eps) d[i][j] = d[i][k] + d[k][j];
printf("%.2f\n", d[][n]);
}
}
E题 贪心算法,先排序,最左侧的必须首先覆盖,然后依次类推,不断覆盖,不难证明这是最优的
#include <iostream>
#include <algorithm>
using namespace std;
int a[];
int main()
{
int L, N, l;
cin>>L>>N>>l;
for(int i = ; i <= N; i++) cin>>a[i];
sort(a+, a++N);
int li = -, ans = ;
for(int i = ; i <= N; i++)
{
if(a[i] - li > l)
{
ans++;
li = a[i];
}
}
cout<<ans<<endl;
}
F题 动态规划,利用滚动数组,f[j]表示交易了j次但并未买入一个股票的状态,g[j]表示交易了j次但买入了股票的状态,然后对每一个股票都需要做一个买或者不买的决策,最后输出max(g[j])即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = ;
long long a[N], f[][N*], g[][N*];
int main()
{
long long n, k;
while(cin>>n>>k)
{
k *= ;
for(int i = ; i <= n; i++) cin>>a[i];
memset(f, , sizeof(f));
memset(g, , sizeof(g));
for(int i = ; i <= n; i++)
{
for(int j = ; j <= k; j++)
{
f[i&][j] = max(g[(i-)&][j-] - a[i], f[i&][j]);
g[i&][j] = max(f[(i-)&][j-] + a[i], g[i&][j]);
g[i&][j] = max(g[(i-)&][j], g[i&][j]);
f[i&][j] = max(f[(i-)&][j], f[i&][j]);
}
}
long long ans = ;
for(int j = ; j <= k; j++) ans = max(ans, g[n&][j]);
cout<<ans<<endl;
}
}
G题 树型背包动态规划,dp[x][m]表示在x结点用了m个火把向下探索所得到的最大价值,然后转移的时候利用dfs转移即可
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = , maxm = ;
vector <int> G[maxn];
int dp[maxn][maxm];
struct thing
{
int l, v;
}a[maxn];
int n, M; void dfs(int x, long long m)
{
for(int i = ; i < G[x].size(); i++)
{
int to = G[x][i];
for(int j = ; j <= (m* - a[to].l)/; j++) dp[to][j] = dp[x][j] + a[to].v;
dfs(to, (m* - a[to].l)/);
for(int j = ; j <= (m* - a[to].l)/; j++)
dp[x][j+(a[to].l+)/] = max(dp[x][j+(a[to].l+)/], dp[to][j]);
}
}
int main()
{
//freopen("a.txt", "r", stdin);
while(cin>>M>>n)
{
for(int i = ; i <= n; i++) G[i].clear();
memset(dp, , sizeof(dp));
int x, y, L, v;
for(int i = ; i <= n; i++)
{
cin>>x;
while(x--)
{
cin>>y>>L>>v;
G[i].push_back(y);
a[y].l = L; a[y].v = v;
}
}
dfs(, M);
cout<<dp[][M]<<endl;
}
}
H题 采药
这个题的背包容量非常大,普通的01背包转移在时间和空间上都无法通过
但由于是随机数据,我们可以利用分块的思想进行优化
初始时先把1~C看成一个大整块
然后第一次更新,用这个大整块去更新出来两个分割的小块
(每一块的值代表从l到r这个容量内的dp值,即dp[l~r]。如果l~r内存在dp值不同的数据,则将这一块分成更多的小块来满足dp值相同的条件)
下一次再用这2个分割的小块去更新出更多的小块
如果仅仅这样做,显然空间和时间上通过也很困难
于是我们每次更新后进行一个维护操作
把值相等且相邻的块合并成一个大块,由于随机数据,每一次维护后,块的数量实际上都非常少(sqrt(n)左右)
于是每次更新的复杂度就是100左右
整体复杂度就是n*sqrt(n)(玄学)
实现过程中,有比较多的细节,要多加注意。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
struct Data
{
LL l, r, v;
Data() {}
Data(LL _l, LL _r, LL _v):l(_l), r(_r), v(_v) { }
};
struct thing
{
LL cost, v;
bool operator <(const thing &B) const
{ return cost > B.cost; }
}a[];
vector <Data> B[];
map<int, LL> M;
int n;
LL t;
int main()
{
while(cin>>n>>t)
{
for(int i = ; i <= n; i++) cin>>a[i].cost>>a[i].v;
sort(a+, a++n);
LL Sum = ;
for(int i = n; i >= n-; i--) Sum += a[i].v;
B[].push_back(Data(, t, ));
for(int i = ; i <= n; i++)
{
B[].clear(); B[].push_back(Data(, min(a[i].cost-, t), ));
for(int j = ; j < B[].size(); j++)
{
Data& e = B[][j];
if(e.l + a[i].cost > t) break;
B[].push_back(Data(e.l + a[i].cost, min(t, e.r + a[i].cost), e.v + a[i].v));
}
for(int j = , k = ; j < B[].size(); j++)
{
if(B[][j].r >= B[][k].l)
B[].push_back(Data(max(B[][j].l, B[][k].l), min(B[][j].r, B[][k].r), max(B[][k].v, B[][j].v)));
if(B[][j].r > B[][k].r) k++, j--;
}
B[].clear(); M.clear();
for(int j = ; j < B[].size(); j++) M[B[][j].v] = B[][j].r;
for(int j = ; j < B[].size(); j++)
{
if(M[B[][j].v])
{
B[].push_back(Data(B[][j].l, M[B[][j].v], B[][j].v));
M[B[][j].v] = ;
}
}
B[].clear();
}
cout<<B[][B[].size()-].v<<endl;
B[].clear();
}
}
I题 逛公园
十分有趣的一道题目,由于它是一个有向的完全图且不存在环
首先先证明这样一个结论
* 如果这个图有n个点且不存在环,那么必定有一个点,它的入度是0,出度是n-1
证明:反证法,如果不存在这样一个点,那么不妨设一个入度最小的点x,它的入度是m,那么出度就是n-m-1
考虑所有指向它的m个点中的一个点y,那么可以得到,y也必定指向所有x指向的(n-m-1)个点(因为如果y不全部指向它们,那么肯定会存在环)
然后y的入度就是n - (n-m+1) = m-1,显然y的入度比x的入度小
所以矛盾,所以一定存在一个点的入度是0
那么接下来把这个点直接删掉(并不会对环的存在有任何影响) ,图就变成了n-1个点,那么我们同样可以得到必定有一个点入度是0,出度是n-2。
以此类推,我们得到这个图不存在环,那么这n个点的入度分别是0,1,2....n-1
也就是我们需要决策这n个点的入度分别是多少,以使改变的边数最少
然后可以用状态压缩DP来解决
dp[i][s]表示选了i个点,状态为s所需要改变的最小边数
那么再选下一个点来更新dp[i+1][s+(1<<i)]
最后答案就是dp[n][(1<<n) - 1]
中间还可以利用位运算优化,把n*n*(2^n)优化为n*(2^n)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std; int M[][];
vector<int> S[];
int dp[(<<)];
int T[(<<)], table[];
int main()
{
int n;
for(int i = ; i < (<<); i++)
{
int temp = ;
for(int j = ; j < ; j++) if((<<j)&i) temp++;
S[temp].push_back(i); T[i] = temp;
}
while(cin>>n)
{
memset(table, , sizeof(table));
memset(dp, , sizeof(dp));
memset(M, , sizeof(M));
for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
cin>>M[i][j];
for(int i = ; i <= n; i++) M[i][i] = ;
for(int i = ; i <= n; i++)
for(int j = n; j >= ; j--)
table[i] = (table[i]<<) + M[i][j]^;
dp[] = ;
for(int i = ; i <= n; i++)
{
for(int j = ; j <= n; j++)
{
for(int k = ; k < S[i-].size(); k++)
{
int s = S[i-][k];
if(<<(j-)&s) continue;
int temp = ;
dp[s + (<<(j-))] = min(dp[s + (<<(j-))], dp[s] + T[table[j]&(~s)]);
}
}
}
cout<<dp[(<<n)-]<<endl;
}
}
J题 过河卒,简单动态规划,把马可以控制的点都删除,然后按照f[i][j] = f[i-1][j] + f[i][j-1]转移就可以
#include <iostream>
#include <cstdio>
using namespace std; long long dp[][];
bool flag[][];
int dx[] = {-, -, , };
int dy[] = {, , , };
int x[], y[];
int main()
{
int xb, yb, N;
cin>>xb>>yb>>N;
for(int i = ; i < N; i++)
cin>>x[i]>>y[i];
for(int i = ; i < ; i++)
{
for(int j = ; j < N; j++)
{
if(x[j] + dx[i] < ) continue;
flag[y[j] + dy[i]][x[j] + dx[i]] = ;
if(y[j] - dy[i] < ) continue;
flag[y[j] - dy[i]][x[j] + dx[i]] = ;
}
}
for(int j = ; j < N; j++) flag[y[j]][x[j]] = ;
flag[][] = ;
dp[][] = ;
for(int j = ; j <= xb; j++)
if(!flag[][j]) dp[][j] = dp[][j-]%((int)1e9+);
for(int i = ; i <= yb; i++)
{
if(!flag[i][]) dp[i][] = dp[i-][];
for(int j = ; j <= xb; j++)
if(!flag[i][j]) dp[i][j] = (dp[i-][j] + dp[i][j-])%((int)1e9+);
}
cout<<dp[yb][xb]<<endl;
}
2016年NK冬季训练赛 民间题解的更多相关文章
- Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)
Contest1592 - 2018-2019赛季多校联合新生训练赛第二场 D 10248 修建高楼(模拟优化) H 10252 组装玩具(贪心+二分) D 传送门 题干 题目描述 C 市有一条东西走 ...
- Contest1585 - 2018-2019赛季多校联合新生训练赛第一场(部分题解)
Contest1585 - 2018-2019赛季多校联合新生训练赛第一场 C 10187 查找特定的合数 D 10188 传话游戏 H 10192 扫雷游戏 C 传送门 题干: 题目描述 自然数中除 ...
- 2017南开ACM校赛(网络赛) 民间题解
orz 首先说一下这个只是民间题解,可能会有很多错误 程序还没有评测,所以可能存在问题 C题比赛的时候没想到..后来发现是个模板题,所以没有代码 希望这份题解能对读者有所启发吧... A题 直接倒序枚 ...
- HDU6578 2019HDU多校训练赛第一场 1001 (dp)
HDU6578 2019HDU多校训练赛第一场 1001 (dp) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6578 题意: 你有n个空需要去填,有 ...
- HDU6579 2019HDU多校训练赛第一场1002 (线性基)
HDU6579 2019HDU多校训练赛第一场1002 (线性基) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6579 题意: 两种操作 1.在序列末 ...
- 2016 CCPC 东北地区重现赛
1. 2016 CCPC 东北地区重现赛 2.总结:弱渣,只做出01.03.05水题 08 HDU5929 Basic Data Structure 模拟,双端队列 1.题意:模拟一个栈的操 ...
- 记2016商大ACM省赛
比赛前三天才得到省赛的非正式参赛名额,总有点哭笑不得,笑的是是我的终究是我的,跑不掉…… 哭的是现在就剩三天了,虽然最近也一直在参加训练赛,但一直是断断续续的,对自己现在的水平并没有太大的信心…… 虽 ...
- 10.0.0.55_12-16训练赛部分writeup
0x1 - MISC MISC100 一张帅行的照片 目测是图片隐写,但是binwalk并没有出来,应该是对文件头进行了修改 010editor查看一下,发现在jpg文件尾之后还有大量的数据 而且在灰 ...
- 7.30 正睿暑期集训营 A班训练赛
目录 2018.7.30 正睿暑期集训营 A班训练赛 T1 A.蔡老板分果子(Hash) T2 B.蔡老板送外卖(并查集 最小生成树) T3 C.蔡老板学数学(DP NTT) 考试代码 T2 T3 2 ...
随机推荐
- java面试题:已知一个数组[2,4,6,2,1,5],将该数组进行排序(降序,不能用工具类进行排序),创建两条线程交替输出排序后的数组,线程名自定义
package com.swift; import java.util.Arrays; import java.util.Comparator; public class ArrayThread_Te ...
- 简单webservice实现(xFire1.2)
基于xfire实现webservice的实例 首先下载xfire的jar包,并导入项目当中 下载地址:http://xfire.codehaus.org/Download 编写实现类 首先建一个接口把 ...
- lintcode_111_爬楼梯
爬楼梯 描述 笔记 数据 评测 假设你正在爬楼梯,需要n步你才能到达顶部.但每次你只能爬一步或者两步,你能有多少种不同的方法爬到楼顶部? 您在真实的面试中是否遇到过这个题? Yes 哪家公司问你的 ...
- SVN中trunk,branches,tags用法详解(转载)
转载出处:http://www.cnblogs.com/dafozhang/archive/2012/06/28/2567769.html Subversion是一个自由开源的版本控制系统.在Subv ...
- jstree 全部选中事件 select_all 使用
select_all function of jstree not checked node for jstree-open branch of ajax-jstree 很尴尬啊,找了整个百度,360 ...
- python 计算提成代码
while True: with open('8564.txt') as f: r = f.readlines() start = input("请输入要查询的日期,例如20180101 : ...
- dts--framework(一)
dts 大体框架 framework 定义类 定义方法 tests framework调用所需要的函数 ./dpdk/usertools/cpu_layout.py /sys/devices/syst ...
- SSO 单点登录总结(PHP)
本篇文章根据个人理解的知识整理汇总,如有不足之处,请大家多多指正. 单点登录(SSO--Single Sign On)的应用是很普遍的,尤其在大型网站系统中,比如百度,登录百度账号和,再转到百度经验. ...
- Go实现mqtt服务
package main import ( "os" "log" "github.com/eclipse/paho.mqtt.golang" ...
- Android 懒加载简单介绍
1.懒加载介绍 1.1.效果预览 1.2.效果讲解 当页面可见的时候,才加载当前页面. 没有打开的页面,就不会预加载. 说白了,懒加载就是可见的时候才去请求数据. 1.3.懒加载文章传送门 参考文章: ...