Loi 模拟赛之压轴出场的互测终曲|(*_-) 模拟+模拟+贪心+bfs+图论+数论

这份题内容比较基础,但是质量很高;
然而我还是GG了;

T1:

Problem 1 :令咒(order.cpp)

题目描述
当你终于打通 Codevs 钻石天梯, 成为一名 Master 后。在 11 月 11 日这一天,
响应万能的评测机的召唤, 加入了恢弘的魔术师战争中。
但评测机却在大战开幕前被污染了//被卡了,意外导致你手背上的令咒排列顺
序被随机打乱, 令咒表现为一长度确定的字符串 B。 而身为古老魔术家族的传
人, 你发现家族世代相传的文献记载了令咒原有的模样为字符串 A, 你考虑对
比两个令咒, 将你手背上的令咒修改为原有的模样, 修改规则如下:
1. 每次可以交换 B 令咒中相邻两个字符的位置。
2. 根据等价交换的准则,修改令咒会消耗魔力, 你想要使 A, B 相同,并希望
交换次数最少。
3. 若无法将 B 修改为 A,输出“-1” 。

输入格式

输入文件 order.in。
第一行一个整数 n,表示字符串的长度
接下来两行,每行一个字符串 A, B。
输出格式
输出文件 order.out。
一个整数为最小交换次数(若不能交换则输出“-1”)
样例输入
5
AB?@C
A?CB@
样例输出
3

数据范围及提示

数据保证不会存在重复字符
对于 20%的数据: 1<=n<=20
对于 100%的数据: 1<=n<=100

好题~
将字母映射为数字,然后求逆序对;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int a[1001],ma[1001],r[1001];
int n,ans;

void merge_sort(int f,int t)
{
    if(f==t) return;
    int mid=(f+t)>>1;
    merge_sort(f,mid),merge_sort(mid+1,t);
    int i=f,j=mid+1,k=i;
    while(i<=mid && j<=t)
        if(a[i]>a[j]) 
            r[k++]=a[j++],ans+=mid-i+1;
        else 
            r[k++]=a[i++];

    while(i<=mid) r[k++]=a[i++];
    while(j<=t) r[k++]=a[j++];
    for(int i=f;i<=t;i++) a[i]=r[i];
    return;
}

void solve()
{
    char c;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    cin>>c,ma[c]=i;
    for(int i=1;i<=n;i++)
    cin>>c,a[i]=ma[c];

    merge_sort(1,n);

    cout<<ans;
}

int main()
{
    freopen("order.in","r",stdin);
    freopen("order.out","w",stdout);
    solve();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T2:

后缀表达式;
不想再写第二遍<-_<-;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const ll MAXN=210;
ll stack[MAXN],a[MAXN];
char stack_f[MAXN],s[MAXN],b[MAXN];
ll len,top,top_f,x,y,tot;

ll get(char c)
{
    switch(c)
    {
        case '(': return 0;
        case '+': return 1;
        case '-': return 1;
        case '*': return 2;
        case '/': return 2;
        case '^': return 2147483647;
    }
}

ll ji(ll x,ll y,char c)
{
    switch(c)
    {
        case '+': return x+y;
        case '-': return x-y;
        case '*': return x*y;
        case '/': return x/y; 
        case '^': return pow(x,y);
    }
}

void done()
{
    while(stack_f[top_f]!='(')
    {
        x=stack[top],--top;
        y=stack[top],--top;
        tot=ji(y,x,stack_f[top_f]);
        top_f--;
        stack[++top]=tot;
    }
    if(stack_f[top_f]=='(') top_f--;
    return;
}



void calc(char c)
{
    if(c==')')
    {
        done();
        return;
    }
    else if(c=='('  || !top_f || get(stack_f[top_f])<get(c))
    { 
        stack_f[++top_f]=c;
        return;
    }
    else if(get(stack_f[top_f])>=get(c))
    {
        while(get(stack_f[top_f])>=get(c) && top_f)
        {
            x=stack[top],top--;
            y=stack[top],top--;
            tot=ji(y,x,stack_f[top_f]);
            top_f--;
            stack[++top]=tot;
        }
        stack_f[++top_f]=c;
    }
    return;
}


void solve()
{
    scanf("%s",s+1);
    len=strlen(s+1);

    for(ll i=1;i<=len;)
    {
        ll f=1;
        if((s[i]=='-' && s[i-1]=='\0') || (s[i]=='-' && s[i-1]=='(')) f=-1,i++;
        if(s[i]>='0' && s[i]<='9')
        {
            ll num=0;
            while(s[i]>='0' && s[i]<='9')
                num=num*10+s[i]-'0',i++;
            stack[++top]=num*f;
        }
        else calc(s[i]),i++;
    }

    while(stack_f[top_f]=='(') top_f--;
    while(top>=2)
    {
        x=stack[top],top--;
        y=stack[top],top--;
        tot=ji(y,x,stack_f[top_f]);
        top_f--;
        stack[++top]=tot;
    }

    cout<<stack[top]<<'\n';
    return;
}

int main()
{
    solve();
    return 0;
}

T3:

你可以在接下来的 N 天内完全预测某种股票的价格,你可以利用这个知识获
利,但每天只能处理一份股票。 也就是说,你每天要么买一份, 要么卖一份,
要么什么也不做。 最初你拥有 0 份股票,当你不拥有任何股票时,你不能出售
股票。
在 N 天结束的时候, 你需要使自己手中的股票为 0, 但希望在 N 天的过程中赚
到尽量多的钱。

输入格式

输入文件 resell.in
第一行输入一个 N 表示天数。
接下来的 N 行每行一个整数 Pi 表示第 i 天某种股票的价格。
输出格式
输出文件 resell.out
一个整数为赚到的最大金额。
样例输入 1
9
10 5 4 7 9 12 6 2 10
样例输出 1
20
样例输入 2
20
3 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 2 3 8 4
样例输出 2
41

数据范围及提示

对于 30%的数据: 1<=n<=10
对于 100%的数据: 1<=n<=300000

代码很简单,但完全不会做~~ ;

首先考虑;
对于某个价格,我们要么”买”,要么”卖”;
如果小于堆顶元素,那么我们将它放入堆中;
如果大于堆顶元素,有两种情况:
1.将股票按堆顶买入,按此价格卖出;
2.此价格对答案不做任何贡献;

1.now-top;
2.存在top < now < a,则a-now+now-top=a-top;
此时now不做任何贡献,但我们已经将它弹出;
后面可能存在f,使得f-now为答案做贡献,即1的情况;
所以我们将堆中放两个now;

这可能是我做的最难的一道贪心了吧……

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
priority_queue<int ,vector<int> ,greater<int> >q;

typedef long long ll;

ll n,ans,x;
void solve()
{
    cin>>n;
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        if(q.empty() || q.top()>=x) q.push(x);
        else 
        {
            ans+=x-q.top();
            q.pop();
            q.push(x),q.push(x);
        } 
    }
    cout<<ans;
}
int main()
{
    freopen("resell.in","r",stdin);
    freopen("resell.out","w",stdout);
    solve();
    fclose(stdin);
    fclose(stdout);
    return 0;
}

T4

题目描述

当 Spike 只身杀入红龙总部,寻找着宿敌 Vicious 时,遇到了过去组织中好友
林的弟弟真。
真告诉 Spike 了 Vicious 的地点,在总部大厦的最顶层。 想要到达那里则必须
经过面前的迷宫防御系统——迷宫如真手中的地图所示:
在一张 N×M 格的矩形迷宫中, Spike 开始时从左上角的格子进入迷宫,出口则
位于右下角的格子。当处于迷宫中时, 可以选择上, 下,左, 右四个方向移动
到相邻的格子中。
可是等等!迷宫中的每一个格子都有一种颜色, 每种颜色代表不同的属性!
• 如果格子是红色的, 说明有红龙干部镇守, 是无法通行的。
• 如果格子是粉红色的,则可以正常行走。
• 如果格子是橙色的, 为红龙干部确认没有入侵者的区域。 可以正常行走,且
经过者会被染上安全标记。
• 如果格子是蓝色的, 为特殊通行区域,仅允许染有安全标记的人通过。
• 如果格子是紫色的, 为快速通行区域, Spike 将沿该方向滑动到下一个格子
(除非他无法穿过)。如果这个格子也是一个紫色的格子,那么将继续滑动,
直到他落在一个非紫色的格子上,或者击中一个无法通行的格子。 同时,若
经过紫色的格子,则会清除身上的安全标记。
(如果你对紫色格子感到困惑,下面的样例将说明它们的用途。)
请帮助 Spike 经尽可能少的移动步数从左上角到达右下角。

输入格式

输入文件 cowboy.in
第一行有两个整数 N 和 M, 表示迷宫的行数(rows) 和列数(columns)。
接下来的 N 行每行各有 M 个整数, 代表迷宫。
• “0”代表是一个红色的格子
• “1”代表是一个粉红色的格子
• “2”代表是一个橙色的格子
• “3”代表是一个蓝色的格子
• “4”代表是一个紫色的格子
左上角和右下角的整数将始终为“1”。
输出格式
输出文件 cowboy.out
一个整数,代表 Spike 必须用来穿过迷宫的最小移动步数,如果不可能穿过,
则输出“-1” 。
样例输入4 4
1 0 2 1
1 1 4 1
1 0 4 0
1 3 1 1
样例输出
10

样例说明

在这个例子中, Spike 向下走一个格子,向右走两个格子(然后向右滑动一个
格子)。他向上走一个格子,向左走一格,向下走一格(再往下滑两个方块),
再向左走一格。这共有 10 个动作(DRRRULDDDR)。

数据范围及提示

对于 100%的数据: 1<=n,m<=1000

注意细节,比如:紫色格子如果无法继续前进,可以转弯……;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

const int MAXN=1001;
int ma[MAXN][MAXN];
bool vis[MAXN][MAXN][6][3];
int n,m;
int X[]={0,1,0,-1,0};
int Y[]={0,0,-1,0,1};
//1上,2右,3下,4左; 
struct hh
{
    int x,y,step,fang,f;
};

bool can(int x,int y)
{
    if(x>=1 && x<=n && y>=1 && y<=m) return true;
    else return false;
}

int bfs()
{
    queue<hh>q;
    hh now;
    q.push((hh){1,1,0,0,0});
    while(!q.empty())
    {
        now=q.front(),q.pop();

        if(now.x==n && now.y==m)
            return now.step;

        if(ma[now.x][now.y]==4)
        {
            int g=now.fang;
            int fx=now.x+X[g],fy=now.y+Y[g];
            if(ma[fx][fy]==1)
            {
                if(!vis[fx][fy][0][now.f])
                {   
                    vis[fx][fy][0][now.f]=1;
                    q.push((hh){fx,fy,now.step+1,0,now.f});
                }
            }
            else if(ma[fx][fy]==2)
            {
                if(!vis[fx][fy][0][1])
                {
                    vis[fx][fy][0][1]=1;
                    q.push((hh){fx,fy,now.step+1,0,1});
                }
            }
            else if(ma[fx][fy]==3 || ma[fx][fy]==0 || !can(fx,fy))
            {
                for(int i=1;i<=4;i++)
                {
                    int fx=now.x+X[i];
                    int fy=now.y+Y[i];
                    if(!can(fx,fy)) continue;

                    if(ma[fx][fy]==1)
                    {
                        if(!vis[fx][fy][0][now.f])
                        {
                            vis[fx][fy][0][now.f]=1;
                            q.push((hh){fx,fy,now.step+1,0,now.f});
                        }
                    }
                    else if(ma[fx][fy]==2)
                    {
                        if(!vis[fx][fy][0][1])
                        {
                            vis[fx][fy][0][1]=1;
                            q.push((hh){fx,fy,now.step+1,0,1});
                        }
                    }
                    else if(ma[fx][fy]==3 && now.f)
                    {
                        if(!vis[fx][fy][0][1])
                        {
                            vis[fx][fy][0][1]=1;
                            q.push((hh){fx,fy,now.step+1,0,1});
                        }
                    }
                    else if(ma[fx][fy]==4)
                    {
                        if(!vis[fx][fy][i][0])
                        {
                            vis[fx][fy][i][0]=1;
                            q.push((hh){fx,fy,now.step+1,i,0});
                        }
                    }
                }
            }
            else if(ma[fx][fy]==4)
            {
                if(!vis[fx][fy][g][0])
                {
                    vis[fx][fy][g][0]=1;
                    q.push((hh){fx,fy,now.step+1,g,0});
                }
            }
        }
        else 
        {
            for(int i=1;i<=4;i++)
            {
                int fx=now.x+X[i];
                int fy=now.y+Y[i];
                if(!can(fx,fy)) continue;
                if(!ma[fx][fy]) continue;

                if(ma[fx][fy]==1)
                {
                    if(!vis[fx][fy][0][now.f])
                    {
                        vis[fx][fy][0][now.f]=1;
                        q.push((hh){fx,fy,now.step+1,0,now.f});
                    }
                }
                else if(ma[fx][fy]==2)
                {
                    if(!vis[fx][fy][0][1])
                    {
                        vis[fx][fy][0][1]=1;
                        q.push((hh){fx,fy,now.step+1,0,1});
                    }
                }
                else if(ma[fx][fy]==3 && now.f)
                {
                    if(!vis[fx][fy][0][1])
                    {
                        vis[fx][fy][0][1]=1;
                        q.push((hh){fx,fy,now.step+1,0,1});
                    }
                }
                else if(ma[fx][fy]==4)
                {
                    if(!vis[fx][fy][i][0])
                    {
                        vis[fx][fy][i][0]=1;
                        q.push((hh){fx,fy,now.step+1,i,0});
                    }
                }
            }
        }
    }
    return -1;
}

void solve()
{

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&ma[i][j]);

    cout<<bfs();
    return;
}

int main()
{
    solve();
    return 0;
}

T5:

Problem 5 :胧村正(blade.cpp)

这个世界中有数把妖刀,那是一旦被拔出来就必须要吸血的刀。
那是元禄年间,将军德川纲吉统治的时代。原本充满神气的名刀长
时间被充满憎恨的血潮所侵染从而转化为充满阴气与妖气的妖刀,
太平盛世下的烟云下,围绕妖刀进行争斗的人们,其欲望、仁义、
迷惘、纷争引来了魑魅魍魉[chī mèi wǎng liǎng],将龙神鬼
神也卷入了战火的劫难之中。
胧夜千十的高徒, 灵魂误入百姬身体饭纲阵九朗为寻找恢复原状的方法而踏上
前往信浓的道路。
怪僧:「阵九朗…国内到处都有护法的结界。你已经无处可逃了,
我要代替诸佛,惩罚你恶逆无道的行径!」
题目描述
现在阵九郎行至甲斐, 怪僧在甲斐通往信浓的道路上设置了一个结界, 结界有
一定的初始防御值, 使用两把妖刀施展二天一流剑技(Star Burst Stream)可以降
低结界防御值, 只有将结界防御值降低到特定的临界防御值才可以破坏结界。
妖刀可以到周围的城镇收集(甲斐不存在妖刀), 部分城镇也不存在妖刀。城镇
由若干条道路连接, 道路两端的城镇可通过这条道路相互到达。 每把妖刀各不
相同,一把妖刀单次攻击可以减少结界特定的防御值,减少量为妖刀的攻击
力, 每次使用妖刀会使妖刀的磨损值减少, 减少量为妖刀的韧度。当磨损值小
于 0 时妖刀将折断无法再次使用。
部分妖刀存在瑕疵,使用此种妖刀攻击结界反而会使结界防御值增加。
阵九郎答应用黑光太刀做报酬, 首先请你帮忙确定两个城镇,使得从甲斐出发
经过尽量短的路程之和, 若距离相等,则选择序号较小的城镇, 找到城镇中的
两把妖刀,且选择城镇中的妖刀在各使用一定次数后可以破坏结界。同时, 妖
刀作为罕见的珍宝,阵九郎希望在使用这两把妖刀破坏结界时消耗的磨损值之
和尽量小,如果预测一把妖刀将中途折断且之后将无法破坏结界, 他将适当减
少此妖刀的使用次数。(即不会使用让妖刀折断的方案) 若无论如何调整都无法
破坏结界,他将把这两把妖刀都舍弃而到另外两个距甲斐路程之和次小的城镇
寻找新的两把妖刀使用, 以此类推。 请你计算结界被破坏后使用的两把妖刀各
自消耗的磨损值。
注:信浓并不在给出城镇中, 且给出的城镇均可到达。
路程之和的定义为: 从起点分别到两点的距离相加
两把妖刀都必须至少使用一次。输入格式

输入文件 blade.in

首先输入 1 行 4 个整数 n,m,h,p 表示城镇总数(甲斐的编号为 1),道路总数,
结界初始防御值及结界临界防御值。
接下来 m 行,每行 3 个整数 u,v,w 表示 u,v 之间存在一条长度为 w 的道路。
接下来 n 行,每行 4 个整数 ci,ri,mi,ti 表示编号为 i 的城镇中妖刀的攻击
力, 韧度,初始磨损值及是否存在瑕疵。完美的妖刀 ti 为 0,存在瑕疵的妖刀
ti 为 1,不存在妖刀的城镇 ci,ri,mi,ti 都为 0。

输出格式

输出文件 blade.out
输出共 1 行, 2 个整数 a,b(a

样例输入

6 6 20 2
1 2 3
2 3 2
1 3 7
2 4 1
3 5 4
5 6 2
0 0 0 0
0 0 0 0
5 2 11 0
10 3 10 0
2 1 6 04 4 15 0

样例输出

5 8

数据范围及提示

对于 30%的数据: 1<=n,m<=40000
对于 100%的数据: 1<=n, m<=200000, 1<=ci<=10000, 1<=ri<=1000,
1<=mi<=10000
附真实地图,与题目无关。

改天再弄吧……;

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值