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冬季训练赛 民间题解的更多相关文章

  1. Contest1592 - 2018-2019赛季多校联合新生训练赛第二场(部分题解)

    Contest1592 - 2018-2019赛季多校联合新生训练赛第二场 D 10248 修建高楼(模拟优化) H 10252 组装玩具(贪心+二分) D 传送门 题干 题目描述 C 市有一条东西走 ...

  2. Contest1585 - 2018-2019赛季多校联合新生训练赛第一场(部分题解)

    Contest1585 - 2018-2019赛季多校联合新生训练赛第一场 C 10187 查找特定的合数 D 10188 传话游戏 H 10192 扫雷游戏 C 传送门 题干: 题目描述 自然数中除 ...

  3. 2017南开ACM校赛(网络赛) 民间题解

    orz 首先说一下这个只是民间题解,可能会有很多错误 程序还没有评测,所以可能存在问题 C题比赛的时候没想到..后来发现是个模板题,所以没有代码 希望这份题解能对读者有所启发吧... A题 直接倒序枚 ...

  4. HDU6578 2019HDU多校训练赛第一场 1001 (dp)

    HDU6578 2019HDU多校训练赛第一场 1001 (dp) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6578 题意: 你有n个空需要去填,有 ...

  5. HDU6579 2019HDU多校训练赛第一场1002 (线性基)

    HDU6579 2019HDU多校训练赛第一场1002 (线性基) 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6579 题意: 两种操作 1.在序列末 ...

  6. 2016 CCPC 东北地区重现赛

    1. 2016 CCPC 东北地区重现赛 2.总结:弱渣,只做出01.03.05水题 08   HDU5929 Basic Data Structure    模拟,双端队列 1.题意:模拟一个栈的操 ...

  7. 记2016商大ACM省赛

    比赛前三天才得到省赛的非正式参赛名额,总有点哭笑不得,笑的是是我的终究是我的,跑不掉…… 哭的是现在就剩三天了,虽然最近也一直在参加训练赛,但一直是断断续续的,对自己现在的水平并没有太大的信心…… 虽 ...

  8. 10.0.0.55_12-16训练赛部分writeup

    0x1 - MISC MISC100 一张帅行的照片 目测是图片隐写,但是binwalk并没有出来,应该是对文件头进行了修改 010editor查看一下,发现在jpg文件尾之后还有大量的数据 而且在灰 ...

  9. 7.30 正睿暑期集训营 A班训练赛

    目录 2018.7.30 正睿暑期集训营 A班训练赛 T1 A.蔡老板分果子(Hash) T2 B.蔡老板送外卖(并查集 最小生成树) T3 C.蔡老板学数学(DP NTT) 考试代码 T2 T3 2 ...

随机推荐

  1. UVA_10139

    The factorial function, n! is defined thus for n a non-negative integer:0! = 1 n! = n×(n−1)! (n > ...

  2. 返回固定数据的web服务器

    import socket def handle_client(socket_con): """ 接收来自客户端的请求,并接收请求报文,解析,返回 "" ...

  3. 如何在maven中的项目使用tomcat插件

    在pom.xml中引入tomcat7插件,具体示例代码如下: <project> <build> <plugins> <plugin> <grou ...

  4. 近年来爆发的CVE漏洞编号

    1.Office漏洞 Office漏洞是大部分APT组织最喜爱的漏洞,Office在个人办公电脑使用量大,对针对性目标是最佳的外网入口,效果也是最直接的. CVE编号  漏洞类型 使用组织 CVE-2 ...

  5. 【Python3】操作文件,目录和路径

    1.遍历文件夹和文件  Python代码   import os import os.path rootdir = "d:/test" for parent,dirnames,fi ...

  6. python__基础 : sys模块: sys.argv与sys.path

    sys模块中的 argv 保存的是当你运行一个py文件的时候给他传递进去的参数,如: import sys a = sys.argv print(a) # 当在命令行中调用这个py文件: > p ...

  7. google云函数实现BigQuery数据操作

    Google Cloud Function操作BigQuery数据库. 1.部署云函数时在配置文件中(package.json)添加一项 "@google-cloud/bigquery&qu ...

  8. OC中block作方法参数时的用法

    方式一.在传参时直接声明block回调方法. 1. 定义方法: - (int)doTest:(NSString *)name para1:(int)temp1 para2:(int)temp2 suc ...

  9. C++ 基础 初始化列表

    当一个类组合了其他类,或者使用了 const 成员,就要用 初始化列表. Class A {...}; Class B {...}; Class C { private: A a; B b; int ...

  10. copyEvens

    public int[] copyEvens(int[] nums, int count) { int newIndex=0; int i=0; int newArray[] = new int[co ...