5.13 校内模拟赛

。。。

果然是dalao们做难题做多了后

简单题水不起来了吗。。

5.13解题报告

  300分

  T1写了差不多30~40分钟

  T2写了不到5min (当时怀疑有坑..)

  T3推了大概1个多小时的式子, 然后又加上调试差不多一个半小时

  时间分配就这样..感觉T2出的太过简单了..直接是个模板

  T1 并查集 + 乱搞

  T2 快速幂模板

  T3 Dp

T1 : codevs 2796 最小完全图

二次联通门 : codevs 2796 最小完全图

/*
    codevs 2796 最小完全图

    并查集 + 乱搞

    用并查集维护图
    给并查集带个集合中元素大小的权(即该并查集内共有多少点)

    最终的答案就是要合并的两个集合中点数的乘积-1
    因为两个集合中的点都不同, 所以可连得边数就是点数的乘积(size[x] * size[y])
    因为这两个集合中已经有当前边了, 所以注意要减去1

    由于是求最小
    那么边权就是当前边的边权加1啦
    (感觉自己说的很迷..)
    注意每次合并时记得要按祖先来合并并查集的大小
*/
#include <algorithm>
#include <cstdio>

#define Max 100090

void read (int &now)
{
    now = 0;
    register char word = getchar ();
    while (word < ‘0‘ || word > ‘9‘)
        word = getchar ();
    while (word >= ‘0‘ && word <= ‘9‘)
    {
        now = now * 10 + word - ‘0‘;
        word = getchar ();
    }
} 

int N;

long long Answer;

class Unio_Find_Set_Type
{
    private :

        int father[Max];
        int size[Max];

    public : 

        void clear (int N)
        {
            for (int i = 1; i <= N; i++)
            {
                father[i] = i;
                size[i] = 1;
            }
        }

        int Find (int x)
        {
            return father[x] == x ? x : father[x] = Find (father[x]);
        }

        inline void Unio (int x, int y, int dis)
        {
            Answer += (long long) (dis + 1) * ((long long) size[x] * (long long) size[y] - 1);
            size[x] += size[y];
            father[y] = x;
        }
};

Unio_Find_Set_Type ZlycerQan;

class Make_Graph_Type
{
    private :    

        struct Edges
        {
            int from;
            int to;
            int dis;

            bool operator < (const Edges a) const
            {
                return dis < a.dis;
            }
        }

        edge[Max];

        int Edge_Count;
        int now_1, now_2;

    public :

        inline void Add_Edge (int from, int to, int dis)
        {
            Answer += dis;
            Edge_Count++;
            edge[Edge_Count].from = from;
            edge[Edge_Count].to = to;
            edge[Edge_Count].dis = dis;
        }

        void Make ()
        {
            std :: sort (edge + 1, edge + N);
            for (int i = 1; i < N; i++)
            {
                now_1 = ZlycerQan.Find (edge[i].from);
                now_2 = ZlycerQan.Find (edge[i].to);
                ZlycerQan.Unio (now_1, now_2, edge[i].dis);
            }
        }
};

Make_Graph_Type Make;

int main (int argc, char *argv[])
{
    read (N);
    int x, y, z;
    for (int i = 1; i < N; i++)
    {
        read (x);
        read (y);
        read (z);
        Make.Add_Edge (x, y, z);
    }
    ZlycerQan.clear (N);
    Make.Make ();
    printf ("%lld", Answer);
    return 0;
}

T2 : codevs 1497 取余运算

二次联通门 : codevs 1497 取余运算

/*
    codevs 1497 取余运算

    快速幂模板..
    不知道为何不能直接用printf 直接把整个式子输出...
    就只能比较麻烦, 分开输出了..
*/
#include <cstdio>

void read (long long &now)
{
    now = 0;
    register char word = getchar ();
    while (word < ‘0‘ || word > ‘9‘)
        word = getchar ();
    while (word >= ‘0‘ && word <= ‘9‘)
    {
        now = now * 10 + word - ‘0‘;
        word = getchar ();
    }
}

long long Fast_Pow (long long now, long long p, long long Mod)
{
    long long Answer = 1;
    while (p)
    {
        if (p & 1)
            Answer = (Answer * now) % Mod;
        now = (now * now) % Mod;
        p >>= 1;
    }
    return Answer;
}

int main (int argc, char *argv[])
{
    long long x, p, Mod;
    read (x);
    read (p);
    read (Mod);
    printf ("%lld^", x);
    printf ("%lld mod", p);
    printf (" %lld=", Mod);
    printf ("%lld", Fast_Pow (x, p, Mod));
    return 0;
}

T3 : codevs 1257 打砖块

二次联通门 : codevs 1257 打砖块

/*
    codevs 1257 打砖块

    DP

    状态数很好确定
    dp[i][j][k] 表示 打到第i行第j列是第k个被打掉的最大价值
    那么方程就是
    dp[i][j][k] = max (dp[i][j][k], dp[i + 1][p][k - j] + map[j][i])
    map[i][j]是个前缀和
    用来记录(1 ~ i)行中第j列的价值总和
    p是枚举当前列中的位置

    若砖块不是按照顺序打掉的(即类似于一个三角形), 则新开一列
    第0列 即dp[i][0][k], 存的是不打第i列的砖块
    打第i-1列中砖块的最大值
    这样递推一下就可以..
    注意边界条件, 和每一行中的k值的正确求出 

*/
#include <cstdlib>
#include <cstdio>
#include <ctime>

#define Max 105
#define V N - i + 1

void read (int &now)
{
    now = 0;
    register char word = getchar ();
    while (word < ‘0‘ || word > ‘9‘)
        word = getchar ();
    while (word >= ‘0‘ && word <= ‘9‘)
    {
        now = now * 10 + word - ‘0‘;
        word = getchar ();
    }
}

inline int max (int a, int b)
{
    return a > b ? a : b;
}

int N, M;
int dp[Max][Max][Max * 10];
int map[Max][Max];

int main (int argc, char *argv[])
{
    read (N);
    read (M);
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= V; j++)
        {
            read (map[i][j]);
            map[i][j] += map[i - 1][j];
        }
    int Answer = 0, now;
    for (int i = N; i >= 1; i--)
        for (int j = 0; j <= V; j++)
        {
            now = 0;
            for (int q = 1; q <= j; q++)
                now += q;
            if (j == 0)
                now = 1;
            for (int k = now; k <= M; k++)
                for (int p = j - 1; p <= V; p++)
                    if (p >= 0)
                        dp[i][j][k] = max (dp[i][j][k], dp[i + 1][p][k - j] + map[j][i]);
                    else
                        dp[i][j][k] = max (dp[i][j][k], dp[i + 1][0][k - j] + map[j][i]);
        }
    for (int i = 1; i <= N; i++)
        for (int j = 0; j <= V; j++)
            Answer = max (Answer, dp[i][j][M]);
    printf ("%d", Answer);
    return 0;
}
时间: 2024-11-03 21:04:10

5.13 校内模拟赛的相关文章

2017.6.11 校内模拟赛

题面及数据及std(有本人的也有原来的) :2017.6.11 校内模拟赛 T1 自己在纸上模拟一下后就会发现 可以用栈来搞一搞事情 受了上次zsq 讲的双栈排序的启发.. 具体就是将原盘子大小copy一下排个序 用两个指针维护两个数组(原数据 和 排序后的数据), 即分为1数据和2数组 将小于1指针指向的数据的2数组中的数据全部压入栈中 后进行消除, 将栈栈顶元素与当前1数组中的1指针指向的元素进行比较 相同则消除 后重复过程 直至指针超过N 后判断一下是否两个指针都超过了N... #incl

校内模拟赛 Zbq&#39;s Music Challenge

Zbq's Music Challenge 题意: 一个长度为n的序列,每个位置可能是1或者0,1的概率是$p_i$.对于一个序列$S$,它的得分是 $$BasicScore=A\times \sum_{i=1}^{n}{S_i} \tag{1}$$ $$ combo(i)=\left\{ \begin{aligned} &S_i & &i=1 \\ &combo(i-1)+1 & &i\neq 1 ~\mathrm{and}~ S_i=1 \\ &

校内模拟赛:确定小组

  [问题描述] 有n个人坐成一排,这n个人都在某一个小组中,同一个小组的所有人所坐的位置一定是连续的. 有一个记者在现场进行采访,他每次采访都会询问一个人其所在的小组有多少人,被询问的每个人都给出了正确的答案,但是由于时间仓促,记者不一定询问了每个人,我们记录一个长度为n的答案序列,序列的第i个数表示第i个人的回答,如果为0则表示记者没有询问过这个人. 记者发现,对于一些情况,他可以唯一确定这排所有人的分组,而对于另外一些情况则不能,于是记者开始好奇,对于某一个答案序列,他能不能做到这一点,如

校内模拟赛(20170921)

救命啊,救命啊!学长出丧题啦!!! 学长他们压榨我们的劳动力,然后带着我们的成绩跑了,无奈的我们只好玩命的调程序,把学长留给我们的丧题做完(划掉) 65分的rank 1跑路. ----------------我是分割线---------------- T1:粉饰(decorate) [题目描述] 小D有一块被分为n*m个格子的矩形鱼片.为了装饰鱼片,小D决定给每个格子上色.由于小D很喜欢红白,所以小D给每个格子涂上了红色或白色,第i行第j列的格子颜色记为c[i,j].涂完之后,小D想评估这块鱼片

[20180816]校内模拟赛

T1 清理(clear) 问题描述 小 C 最近自己开发了一款云盘软件,目前已有??个用户.小C 的云盘上的文件会被后台分成两种类型,活动 文件和非活动文件,活动文件即可能常用的文件,会被放在高速服务器上给用户提供高速下载服务.用户 上传一个文件时,这个文件会被设置为活动文件.由于高速服务器内存大小有限,小 C 需要把一些文件 设为非活动文件,有以下两种设置方式:1.把上传时间前??早的文件全部设为非活动文件:2.把第??个用户上 传的文件全部设为非活动文件.注意这两种方式操作的对象都是所有文件

校内模拟赛T1大美江湖

这就是一个模拟题,注意1234分别对应左右上下横坐标和纵坐标的判断就好了 题解: 需要注意的是,向上取整ceil函数是对于一个double值返回一个double值,也就是说在ceil里面的类型一定要是double,否则会炸 代码: #include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<cstring> #include<string>

校内模拟赛20170604

香蕉锤--双向链表 #include<iostream> #include<cstdio> using namespace std; inline int read(){ int num=0,t=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();} ret

校内模拟赛(20170924)

四校很丧,但是学长的题目更简单 lrb学长的题目为什么都要倒着切,不懂QAQ ----------------我是分割线---------------- T1:个人卫生综合征 每天BBS都要从家里经过城市中的一段路到学校刷五三.城市中一共有n个路口和m条双向道路,每条双向道路都连接着两个路口ai.bi且有一定的时间花费vi.BBS家编号为1,学校编号为n.今天,BBS由于个人卫生综合征导致他很迟才离开家,他想用膜法改变k条道路的长度使通过其的时间花费vi变为0.现在他问你改变道路长度之后他到学校

校内模拟赛(20170917)

这套题目也是比较恶心的,....都是奇技淫巧的说. ----------------我是分割线------------------ T1:消消乐(tet) [题目描述] 有一个2n个数字排成一列,这个数列中由1..n中的数字组成,每个数字都恰好出现两次.每个回合可以交换相邻两个数字,交换以后如果有两个相同的数字相邻,那么将这两个数字消除,并将这两个数字的两端拼起来:如果拼接后的数列仍有相同的数字相邻,那么将引发连锁反应直到没有两个相同数字相邻.现在你想知道最少需要几个回合可以消除所有的数字. [