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

来源:互联网 发布:gartner云计算 编辑:程序博客网 时间:2024/05/21 10:00

这份题内容比较基础,但是质量很高;
然而我还是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
附真实地图,与题目无关。

改天再弄吧……;