2016年NK冬季训练赛 民间题解

A题 水题,考察对行的读入和处理,注意使用long long

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main()
{
  char ch;
  long long a, sum=0, Min;
  char S[200];
  while(cin.getline(S, 100))
  {
        Min = 1e9; a = 0;
        for(int i = 0; i < strlen(S); i++)
        {
          if(S[i] == ‘ ‘)
            {
                Min = min(Min, a);
                a = 0;
            } else
                a = a*10 + S[i] - ‘0‘;
        }
        if(a != 0) 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[100500];
int main()
{
    long long n, k;
    while(cin>>n>>k)
    {
        for(int i = 0; i < n; i++) cin>>a[i].x>>a[i].y;
        sort(a, a+n);
        int ans = -1;
        for(int i = 0; i < n; i++)
        {
            if(k < a[i].y) break;
            k += a[i].x;
            ans = i;
        }
        cout<<ans+1<<endl;
    }
}

C题 可以用dp做,如果把dp的转移方程变成一个矩阵,那么这个矩阵恰好就是这个图的邻接矩阵,然后只要求它的k次幂即可,注意存在自环和重边的情况

  这里可以利用矩阵乘法的一个优化,可以把常数优化很多。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <iomanip>
using namespace std;
const int mod = 999983;
const int maxn = 111;
int n,m;
struct Matrix
{
    long long v[maxn][maxn];
    int n;
    Matrix() { memset(v, 0, sizeof(v));}
    Matrix operator *(const Matrix &B)
    {
        Matrix C; C.n = n;
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
            {
                if(v[i][j] == 0) continue;
                for(int k = 0; 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 = 0; i < n; i++) ans.v[i][i] = 1;
    while(k)
    {
        if(k&1) ans = ans*A;
        A = A*A; k >>= 1;
    }
    return ans;
}
int a, b, k, t;
int main()
{
    while(cin>>n>>m>>k>>t)
    {
        A.n = n;
        for(int i = 1; i <= m; i++)
        {
            scanf("%d %d", &a, &b);
            A.v[a-1][b-1]++;
            if(a != b) A.v[b-1][a-1]++;
        }
        B = power(A, k);
        while(t--)
        {
            scanf("%d %d", &a, &b);
            printf("%d\n", B.v[a-1][b-1]);
        }
    }
    return 0;
}

D题 建图后直接floyed即可,在树上的边权是距离除以速度v,然后再枚举出在同一x坐标的两个点,边权为自由落体的时间。(这里代码有个bug,更新边权要用min的方法更新)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
double eps = 1e-10;
double d[111][111];
struct point
{
    double x, y;
}p[111];
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 = 1; i <= n; i++)
        for(int j = 1;  j <= n; j++)
             d[i][j] = 1e8;
    for(int i = 1; i <= n; i++)
    {
        cin>>p[i].x>>p[i].y>>f;
        if(f == 0) continue;
        d[i][f] = dis(p[i], p[f])/v;
        d[f][i] = d[i][f];
    }
    for(int i = 1; i <= n; i++)
        for(int j = 1; 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)*2/10.0);
        }
    for(int k = 1; k <= n; k++)
        for(int i = 1; i <= n; i++)
            for(int j = 1; 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[1][n]);
    }
}

E题 贪心算法,先排序,最左侧的必须首先覆盖,然后依次类推,不断覆盖,不难证明这是最优的

#include <iostream>
#include <algorithm>
using namespace std;
int a[10000];
int main()
{
    int L, N, l;
    cin>>L>>N>>l;
    for(int i = 1; i <= N; i++) cin>>a[i];
    sort(a+1, a+1+N);
    int li = -1000, ans = 0;
    for(int i = 1; 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 = 10050;
long long a[N], f[2][N*2], g[2][N*2];
int main()
{
    long long n, k;
    while(cin>>n>>k)
    {
        k *= 2;
        for(int i = 1; i <= n; i++)    cin>>a[i];
        memset(f, 128, sizeof(f));
        memset(g, 0, sizeof(g));
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= k; j++)
            {
                f[i&1][j] = max(g[(i-1)&1][j-1] - a[i], f[i&1][j]);
                g[i&1][j] = max(f[(i-1)&1][j-1] + a[i], g[i&1][j]);
                g[i&1][j] = max(g[(i-1)&1][j], g[i&1][j]);
                f[i&1][j] = max(f[(i-1)&1][j], f[i&1][j]);
            }
        }
        long long ans = 0;
        for(int j = 0; j <= k; j++) ans = max(ans, g[n&1][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 = 111, maxm = 111111;
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 = 0; i < G[x].size(); i++)
    {
        int to = G[x][i];
        for(int j = 0; j <= (m*10 - a[to].l)/10; j++) dp[to][j] = dp[x][j] + a[to].v;
        dfs(to, (m*10 - a[to].l)/10);
        for(int j = 0; j <= (m*10 - a[to].l)/10; j++)
            dp[x][j+(a[to].l+9)/10] = max(dp[x][j+(a[to].l+9)/10], dp[to][j]);
    }
}
int main()
{
    //freopen("a.txt", "r", stdin);
    while(cin>>M>>n)
    {
        for(int i = 1; i <= n; i++) G[i].clear();
        memset(dp, 0, sizeof(dp));
        int x, y, L, v;
        for(int i = 1; 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(1, M);
        cout<<dp[1][M]<<endl;
    }
}

H题挖坑

时间: 2024-10-07 01:27:30

2016年NK冬季训练赛 民间题解的相关文章

新生训练赛002题解

------------恢复内容开始------------ J 新年快乐!!! I 十进制中的二进制: 题目hkhv学长最近对二进制数很感兴趣,喜欢一切0和1组成的数.现在有一个十进制整数n,问你1到n之间有多少个数是只有0和1组成的类似二进制的数,输出他们的个数.Input输入数据包含一个数n (1 <= n <=10^9).Output输出1到n中类似二进制的数的个数.Sample Input10Sample Output2Hint对于n = 10,1 和 10是类似二进制的数. 思路:

周一训练赛题解

这次完全是水题大集合啊,希望大家A的开心: 前两个题是我找的,后两个是陶叔找的,另外因为我的偷懒,下面所有的代码都是陶叔亲自写的,十分感谢陶叔: 陶叔暑假为了大家的集训,牺牲了很多自己宝贵的时间,大家接下来要好好训练啊!!!! 废话少说,进入正题: Problem A      SPOJ QUEST5 签到题: 将所有的边按照右端点排个序,然后每次选择没有钉住的点,然后把这之后的所有与它相交的边全去掉: 代码: #include <cstdio> #include <cstring>

cumt训练赛题解

2017年4月3日 cumt2017春季--训练赛(1) A.HihoCoder 1339 (dp) 思路: 比较清晰呢,就是个dp吧.定义一下状态,dp[i][j]:前i个骰子,扔出点数和为j的方案数.然后不就很好写了嘛递推式,dp[i][j] = dp[i - 1][j - k](1<=k<=6). 好像题就做完了诶,可是窝wa了两发什么鬼.第一发爆int,第二发爆longlong,这里的trick就是方案数可能非常大,所以这题的应该把状态定义为dp[i][j]:前i个骰子,扔出点数和为j

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&#39;s problem(manacher+二分/枚举)

HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分相同,第一部分与第二部分对称. 现在给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法,求出以第i个点为中心的回文串长度,记录到数组p中 要满足题目所要求的内容,需要使得两个相邻的回文串,共享中间的一部分,也就是说,左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也是一样. 因为我们已经记录下来以

HDU 5371 (2015多校联合训练赛第七场1003)Hotaru&amp;#39;s problem(manacher+二分/枚举)

pid=5371">HDU 5371 题意: 定义一个序列为N序列:这个序列按分作三部分,第一部分与第三部分同样,第一部分与第二部分对称. 如今给你一个长为n(n<10^5)的序列,求出该序列中N序列的最大长度. 思路: 来自官方题解:修正了一些题解错别字(误 先用求回文串的Manacher算法.求出以第i个点为中心的回文串长度.记录到数组p中 要满足题目所要求的内容.须要使得两个相邻的回文串,共享中间的一部分,也就是说.左边的回文串长度的一半,要大于等于共享部分的长度,右边回文串也

2017后期 第 1 场训练赛

题目依次为 NKOJ 上 P3496 P4236 P3774 P2407 1.数三角形 方法很多, 比如推出三边 x y z 的限制关系, 然后加加减减得到计算式子 不过也可以用观察法, 暴力计算出 n 为 1 至 13 对应的结果为: 0 0 0 1 3 7 13 22 34 50 70 95 125 相邻两数差为: 0 0 1 2 4 6 9 12 16 20 25 30 这些相邻两数相邻差又为: 0 1 1 2 2 3 3 4 4 5 5 找到规律了, 如果结果第 i 项为第 i - 1

EXAM个人训练赛四

EXAM个人训练赛四 已完成 [x] A [x] D [x] E [x] F [x] J [x] K [x] I* 未完成 [x] B [x] C [x] G [x] H 签到水题 A J F A:英文字母有2426个 J:注意long long D:Transit Tree Path 我直接套了单源最短路的一个模板,有人用的是DFS,模板第一次用,记得是无向图. 代码又臭又长: #include<bits/stdc++.h> using namespace std; const int ma

EXAM个人训练赛五

EXAM个人训练赛五 已完成 [x] A [x] E [ ] K* [x] M* 未完成 [ ] C [ ] F 放弃没人做出来的题 A 要用ll,然后注意正方形的情况,细心一点 E 有点动态规划的感觉,状态的转移,不难,要注意不要漏掉状态 K 正解是DFS 然后用贪心数据弱的话能过,先排圆心 M 树状数组,可以维护前面有多少数比这个数小,然后通过相减也可以得出后面有多少数比它小,后面要用到容斥的思想 12xx(xx比1 2大)可以通过组合数算出,即前面比它小的选一个,后面比它大的选两个,然后相

1780 - 2019年我能变强组队训练赛第十八场

题目描述 wls有一个钟表,当前钟表指向了某一个时间. 又有一些很重要的时刻,wls想要在钟表上复现这些时间(并不需要依次复现).我们可以顺时针转动秒针,也可以逆时针转动秒针,分针和时针都会随着秒针按规则转动,wls想知道秒针至少转动多少角度可以使每个时刻至少都会被访问一次. 注意,时钟上的一种时针分针秒针的组合,可以代表两个不同的时间. 输入 第一行一个整数n代表有多少个时刻要访问. 第二行三个整数h,m,s分别代表当前时刻的时分秒. 最后n行每一行三个整数hi,mi,si代表每个要访问的时刻