东北师范大学程序设计竞赛正式赛( A-F + I )

    参加的最后一场校赛,明年大三就看着学弟学妹们打了,最后一年还是侥幸拿了个一等奖,两年一等奖美滋滋,运气大于实力。

A

Problem Description

meopass和ToRapture玩游戏,有nn堆石子,每堆石子有a_iai的重量。
两人轮流行动,ToRapture先手。每次ToRapture会拿若干堆总重量为奇数的的石子,而meopass会拿若干堆总重量为偶数的的石子,两个人都会采取最优行动策略,无法行动的人输。
meopass花了10分钟(天)完全了解这个游戏了,他知道了这个游戏的必胜方法,于是他自己带了很多很多的石子,想要在游戏开始前作弊,通过选取一些堆,在上面添加一些自己带来的石子,从而保持自己的必胜。
问他最少需要带多少石子才能保证自己的胜利?

Input

TT次询问,每组样例第一行包含正整数nn,含义如上。
T = 10, 1 \leq n \leq 10^6, 1 \leq a_i \leq 10^9T=10,1n106,1ai109

Output

对于每次询问输出一个答案,每个答案占一行。

Sample Input
1
2
2 1
Sample Output
1

A题:所以ToRapture是从 总质量为奇数的堆 中 选择若干堆拿走? 还是从 若干堆中拿走总质量为奇数的石子? 还是从所有堆中选择出 若干堆总质量为奇数的堆,然后把它们拿走?还是blablabla.....

出题人说我俩的语文老师不是同一个人...那当然不是同一个人啊,一道水题WA了三发,每一发都觉得自己读题是对的。最后AC。只需要把所有奇数堆的石子全部补成偶数就可以了。Orz。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e6+5;
int a[maxn];

int main()
{
    int T, n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        int sum=0;
        for(int i=0; i<n; i++)
        {
            scanf("%d", &a[i]);
            if(a[i]%2==1) sum++;
        }
        printf("%d\n", sum);
    }
}



B

Problem Description

meopass在101一不小心睡着了。
睡梦中的他进入了一个美丽的三维空间,空间里有nn个旅游景点,他们的位置为(x_i, y_i, z_i)(xi,yi,zi),景点间的距离是欧氏距离(欧几里得距离,例如二维的欧氏距离就是勾股定理)。
但是这nn个景点都是独立的,空间的主人希望他建一些桥梁,从而把这nn个景点连接起来,不然就永远把他囚禁在这里。每个桥梁连接两个不同的景点,桥梁的造价就是这两个景点间的距离。
问他需要花费的最少价钱是多少,因为花的太多的话空间的主人就会不高兴了QAQ。

Input

TT次询问,每组样例第一行包含正整数nn,含义如上。
T = 5, 1 \leq n \leq 1000, -1000 \leq x_i, y_i, z_i \leq 1000T=5,1n1000,1000xi,yi,zi1000

Output

对于每次询问输出一个答案,每个答案占一行,保留小数点后两位有效数字。

Sample Input
1
2
1 1 1
2 2 2
Sample Output
1.73

B题:三维空间下的最小生成树问题,但是其实我们只需要O(n^2)处理出任意两点之间的距离就成了一个最小生成树的裸题了。开场看出题意懒得找板子一直没动,结果还拿了一血...Orz

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e6+5;
const int maxm = 1e3+5;


int pre[maxn];

int found(int x)
{
    if(pre[x]==-1) return x;
    else return pre[x] = found(pre[x]);
}



struct Node{
    int x, y, z;
}node[maxm];

struct Edge{
    double l;
    int a, b;
    bool operator <(const Edge &b)const{
        return l<b.l;
    }
}edge[maxn];

double getl(int i, int j)
{
    double x = node[i].x - node[j].x;
    double y = node[i].y - node[j].y;
    double z = node[i].z - node[j].z;

    return sqrt(x*x+y*y+z*z);
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        memset(pre, -1, sizeof pre);
        int n, cnt = 0;
        scanf("%d", &n);
        for(int i=0; i<n; i++)
            scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].z);
        for(int i=0; i<n; i++)
            for(int j=i+1; j<n; j++)
            {
                edge[cnt].l = getl(i, j);
                edge[cnt].a = i;
                edge[cnt].b = j;
                cnt++;
            }

        sort(edge, edge+cnt);

//        for(int i=0; i<cnt; i++)
//            printf("%f\n", edge[i].l);

        int sum = 0;
        double ans = 0;
        for(int i=0; i<cnt; i++)
        {
            int u = edge[i].a;
            int v = edge[i].b;
            double w = edge[i].l;
            int t1 = found(u);
            int t2 = found(v);
            if(t1!=t2)
            {
                ans += w;
                pre[t1] = t2;
                sum++;
            }
            if(sum==n-1) break;
        }

        printf("%.2f\n", ans);
    }
}



C

Problem Description

axp非常喜欢一款技术性超强的抽卡赌博游戏,它改编自知名牌类游戏比大小。游戏开始时牌库中有3030张卡牌,开局先从牌库中抽33张牌,之后每回合可以抽一张牌(也就是说第一回合开始时,你实际上起了3+1=43+1=4张牌),然后再出一张牌。
牌库中有两种牌,每张牌都有一个价值:
1.1.随从牌,价值为v(1\leq v \leq1000)v(1v1000),使用一张价值为vv的卡牌会为你召唤一名随从,每回合这个随从都可以攻击敌人一次造成vv点伤害。在召唤出随从后,这名随从不能立刻攻击,需要等到下回合才可以第一次攻击敌人。
2.2.一种神奇的卡牌“右手第一张”。这种卡牌的价值为00,但使用这张卡牌之后,你会情不自禁地向敌人致敬:“抱歉”,同时直接对敌人造成10001000点伤害。
现在axp和meopass要在这款游戏中一决高下。axp担心会惨败,于是开了透视外挂看穿了牌库中的3030张牌。
请你帮axp制定出牌策略,使得meopass受到尽量多的伤害。

Input

第一行一个整数TT,代表数据组数。
接下TT组数据,每组数据一行3030个数,其中第ii个数代表牌库中第ii张卡牌的价值。
输入保证合法。

Output

输出4040回合后axp对meopass造成的伤害总和。

什么,你问卡抽完了怎么办?继续打呗=v=
每组数据输出一行,包含一个整数作为答案。

Sample Input
3
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
Sample Output
29039
735
29013

C题:一眼炉石的世界观,作为炉石传说玩家怎么可能不会这道题呢,直接模拟,贪心每回合打出手上攻击力最高的随从。如愿一些,不负传说之名。Orz

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e6+5;
int a[41];
int have[5];

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int sum = 0;
        for(int i=0; i<30; i++)
            scanf("%d", &a[i]);
        for(int i=0; i<3; i++)
            have[i] = a[i];
        for(int i=3; i<30; i++)
        {
            have[3] = a[i];
            sort(have, have+4);
            if(have[3]==0) sum+=1000;
            else sum += have[3]*(40-i+2);
        }
        for(int i=0; i<3; i++)
        {
            if(have[i]==0) sum+=1000;
            else sum += have[i]*(10+i);
        }

        printf("%d\n", sum);
    }
}


D

Problem Description

ToRapture在学习编程的时候发现Golang的package之间不能循环依赖。 例如在Golang中,若package A依赖package B,package B又依赖package A,则无法构建项目。 给出若干package之间的依赖关系,请你判断出能否成功构建项目。

Input

多组输入,每组的第一行为两个非负整数N,MN,M,表示共有NN个package和MM条依赖关系, 接下来的一行为NN个只由大小写字母组成的互不相同的字符串p_1, p_2 \cdots p_np1,p2pn,每个字符串p_ipi最多16个字符,字符串间用空格分割。 接下来的MM行,每行两个字符串p_i, p_jpi,pj,表示p_ipi依赖p_jpj。 \sum N \le 10^5, \sum M \le 5 \times 10^5N105,M5×105

Output

对于每组数据,若可以成功构建,即没有循环依赖,则输出一行"Citrus Saikou!",否则输出一行"DameDameYo",输出双引号内的内容。

Sample Input
4 5
mei yuzu matsuri harumi
mei yuzu
harumi yuzu
harumi mei
matsuri mei
matsuri harumi
5 4
A B C D E
B A
C A
D B
E C
3 1
str os sys
os str
4 4
socket redis kv data
redis socket
kv redis
data kv
redis data
Sample Output
Citrus Saikou!
Citrus Saikou!
Citrus Saikou!
DameDameYo

D题:用map处理String和int之间的对应关系,然后就变成了一个有向图判环的问题。有向图判环用拓扑排序也好,什么连通性算法也好,floyd能不能判有向图的环我都忘了,场上真的是一脸懵逼,于是就鸵了一段时间,最后没办法码了一发DFS染色判环过的,Orz

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+5;

map<string, int>s;

int vis[maxn], rd[maxn];
bool huan = false;
int cnt;

void dfs(vector<int >v[], int x, int val)
{

    //printf("%d: %d\n", x, val);
    for(int i=0; i<v[x].size(); i++)
    {
        if(vis[v[x][i]] == val){
            //printf("**%d %d\n", x, v[x][i]);
            huan = true;
            return ;
        }
        else {
            vis[v[x][i]] = val;
            dfs(v, v[x][i], val);
            vis[v[x][i]] = 0;
        }
    }
}

int main()
{
    int n, m;
    string str, s1, s2;
    while(cin>>n>>m)
    {
        vector<int >v[maxn];
        memset(vis, -1, sizeof vis);
        huan = false;
        s.clear();
        //biaohao
        for(int i=0; i<n; i++)
        {
            cin>>str;
            s.insert(make_pair(str, i));
        }
        //jianbian
        for(int i=0; i<m; i++)
        {
            cin>>s1>>s2;
            v[s[s1]].push_back(s[s2]);
            //printf("#%d %d\n", s[s1], s[s2]);
        }
        int p=1;
        for(int i=0; i<n; i++)
        {
            if(vis[i]==-1)
                dfs(v, i, p++);
        }

//        for(int i=0; i<n; i++)
//        {
//            printf("%d %d\n", i, vis[i]);
//        }

        if(huan) puts("DameDameYo");
        else puts("Citrus Saikou!");
    }
}

E

meopass日常在赛场上摸鱼,并且感慨人生,做不出题目的他一边回忆昨晚吃的烧烤的味道,一边期待着今晚的火锅,随着时间的推移,赛场上过题目的人越来越多,他觉得自己不能再这么颓废下去了,所以他决定:"数气球吧..."

已知现在赛场上共3种颜色的气球,分别是"Red", "Green", "Yellow",分别用'R', 'G', 'Y'来代表。一般而言,赛场上过的最多的题目就是签到题,现在给出赛场上每只队伍的过题情况,你能知道签到题对应的气球是什么颜色吗?

Input

TT次询问,每组样例第一行包含正整数nn,代表场上的队伍数,接下来n行用一个仅包含'R', 'G', 'Y'的字符串表示,代表这个队伍现在拥有哪些气球,每支队伍都不会有重复的气球,签到题可能不唯一。
T = 100, 1 \leq n \leq 10T=100,1n10.

Output

对于每次询问输出一个或多个字符串,多个的情况下按字典序升序输出,表示签到题对应的气球的颜色,每个答案占一行。

Sample Input
1
2
GRY
YR
Sample Output
Red Yellow

E题:开场的水题判一下字符串计数然后判一下最大输出就可以。用first判断单词前需不需要加空格就可以了。运气好拿了个一血。Orz


F

Problem Description

meopass的面前有n个精灵球,虽然他不知道这里面分别装着哪些精灵,但是他知道他们的等级分别是多少,第i个精灵球的等级是v_ivivv是一个11

nn的全排列。
现在他希望从左往右选择kk个精灵球p_1, p_2, \dots, p_kp1,p2,,pk,满足1 \leq p_1 < p_2 < \dots < p_k \leq n1p1<p2<<pkn,且精灵球的等级递增。
meopas并不关心kk有多大,他只想知道有多少种选择的方案。

Input

TT次询问,每组样例第一行包含正整数nn,代表nn个精灵球的等级。
T = 10, 1 \leq n \leq 100000T=10,1n100000

Output

每次询问输出结果占一行,输出答案对100000007100000007取模的结果。

Sample Input
1
2
1 2

F题:F就非常的有意思了,去年校赛就有一个一模一样的求非降(这次是严格上升)子序列的个数,当时现场推的觉得自己巨牛叉,然后下来之后大佬轻飘飘一句这个就是个dp啊觉得自己这么弱怎么还好意思沾沾自喜(当时根本不知道什么事dp)。然后今年这个题开场想了无数种优化办法,最后发现是线段树区间查询就过了....巨弱一开始都没有想到,还手写了一个lazy标记打算区间修改,码了一半发现自己跑偏了...最后因为没有加取模WA了两发,Orz。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e6+5;
const int mod = 100000007;

int a[maxn];

struct Node{
    int l, r;
    int lazy;
    int sum;
}node[maxn];

void init(int n)
{
    node[1].l = 1;
    node[1].r = (1<<n);
    node[1].sum = 0;
    for(int i=2; i<(1<<(n+1)); i++)
    {
        if(i%2==0){
            node[i].l = node[i/2].l;
            node[i].r = node[i/2].l+(node[i/2].r-node[i/2].l+1)/2-1;
            node[i].sum = 0;
        }
        else {
            node[i].l = node[i/2].l+(node[i/2].r-node[i/2].l+1)/2;
            node[i].r = node[i/2].r;
            node[i].sum = 0;
        }
    }
    return;
}

int ask(int l, int r, int i)
{
    if(node[i].l==l && node[i].r==r) return node[i].sum;
    if(node[i*2].r < l) {
        return ask(l, r, i*2+1);
    }
    if(node[i*2+1].l > r) {
        return ask(l, r, i*2);
    }
    return ask(l, node[i*2].r, i*2) + ask(node[i*2+1].l, r, i*2+1);
}

int found(int i, int x)
{
    if(node[i].l==node[i].r)
        return i;
    if(x>node[i*2].r) return found(i*2+1, x);
    return found(i*2, x);
}

void add(int x, int val)
{
    int p = found(1, x);
    node[p].sum = (node[p].sum + val)%mod;
    while(p!=1)
    {
        p = p/2;
        node[p].sum = (node[p].sum + val)%mod;
    }
    return ;
}

int main()
{
    int T, n;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        int topp = 0;
        int m = n-1;
        while((m>>topp)>0) topp++;
        //printf("top:%d\n", topp+1);
        init(topp);


        for(int i=0; i<n; i++)
            scanf("%d", &a[i]);

        for(int i=0; i<n; i++)
        {
            int num = ask(1, a[i], 1);
            //printf("**%d: %d\n", a[i], num);
            add(a[i], num+1);
        }


//        for(int i=1; i<(1<<(topp+1)); i++)
//        {
//            printf("%d: %d %d %d\n", i, node[i].l, node[i].r, node[i].sum);
//        }

        printf("%d\n", node[1].sum%mod);
    }
}

因为是用模拟的思路手敲的线段树,然后第二天就被学妹锤脸拿出了一个更加优美的线段树,拿出来以供自己学习。Orz

struct ss
{
    int l;
    int r;
    int num;
} segt[maxn];
void build(int i,int l,int r)
{
    segt[i].l=l;
    segt[i].r=r;
    if(l==r)
    {
        segt[i].num=num[l];
        return;
    }
    int mid=(r+l)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    segt[i].num=segt[2*i].num+segt[2*i+1].num;
}
void add(int i,int t,int b)
{
    segt[i].num+=b;
    if(segt[i].l==t&&segt[i].r==t)
    {
        //segt[i].num+=b;
        return;
    }
    int mid=(segt[i].r+segt[i].l)/2;
    if(t<=mid)
        add(2*i,t,b);
    else
        add(2*i+1,t,b);

}
int  query(int i,int l,int r)
{
    if(segt[i].r==r&&segt[i].l==l)
        return segt[i].num;
    int mid=(segt[i].l+segt[i].r)/2;
    if(r<=mid)
        query(2*i,l,r);

    else if(l>mid)
        return query(i*2+1,l,r);
    else
        return query(i*2,l,mid)+query(i*2+1,mid+1,r);

}

I

meopass认为字符串的滑稽度等于它里面所有字母的滑稽度之和。每个字母的滑稽度可以由你来分配,不同字母的滑稽度不同,分别对应一个11-2626之间的整数。
他不在乎字母大小写,也就是说字母AAaa的滑稽度相同。
给定一个字符串,输出它的最大可能的滑稽度。
例如:daddad,你可以将2626分配给dd2525分配给aa,这样整个字符串滑稽度为7777

Input

数据包含多组样例,处理到文件尾。
输入一个字符串S, |S| \leq 10000S,S10000,S中没有除字母外的其他字符。

Output

由你将11-2626分配给不同的字母,使得字符串S的滑稽度最大,输出这个滑稽度。

Sample Input
Dad
Sample Output
77

I题:签到用的水题,一开始没注意多组样例WA了一发,只需要对26个数字计数然后排序然后计算就可以了。

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e4+5;

char a[maxn];
int cnt[50];

int main()
{
    while(scanf("%s", a)!=EOF)
    {
        int lena = strlen(a);
        memset(cnt, 0, sizeof cnt);
        for(int i=0; i<lena; i++)
        {
            if(a[i]>='a' &&  a[i]<='z') a[i]-=32;
            //printf("%c", a[i]);
            cnt[a[i]-'A'+1]++;
        }
        int sum = 0;
        sort(cnt+1, cnt+27);
        for(int i=26; i>0; i--)
        {
            //printf("%d: %d\n", i, cnt[i]);
            sum += i*cnt[i];
        }
        printf("%d\n", sum);
    }
}



这次过题的顺序是 E->I->A->C->B->D->F。其中E开场一血后看有人过了A题想着没有一血拿了就去开I题,结果I题judge有问题连WA三发,然后扭回头去看A题又搞不懂出题人的意思又不知道怎么做又WA了两发,然后心态就崩掉了。这个时候被告知I题rejudge,A题再莽两发终于搞懂题意AC,三题后暂居榜首(一位老学长这个时候被打了星hhh)CBD三题连续1A过,然后和场上一群人一起在啃F题,想到数据结构想到线段树模拟遂过。没有被长理锤得太惨还是比较开心的,最后四题一血侥幸拿一等奖还是很开心的,校赛的退役之战hhh。同时向不知名大佬低头,全场被压一点脾气都没有Orz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值