ACM——模拟(hard) 刷题总结

目录

  • 走路模拟器
  • 一.
  • 二.

有一些难度的模拟题

走路模拟器

题意翻译
题目描述
在一条路上,n个房子被排成一排,从从左到右编号为1−n。一开始,你站在1号房子前。你需要移动到其他的房子k次。每一次移动,你不能原地不动(即移动后与移动前,你必须在不同的房子前面)。如果你从x房子移动到y房子,那么你走过的距离就是∣x−y∣,这里∣a∣表示a的绝对值。当然,你可以访问同一个房子多次(只要不连续就行了)你的目标是一共走s个单位长度。如果是不可能的,输出NO,否则输出YES,并输出任意一种移动方案,记住你只能走恰好k次。
输入输出格式
输入格式
第一行包括三个整数n,k,s,分别表示房子的数目,你要移动的次数,和你一共要走的距离。其中2⩽n⩽109,1⩽k⩽2×105,1⩽s⩽1018
输出格式
如果不能用恰好k次移动走过s的距离,输出NO。否则第一行输出YES,然后在第二行输出恰好k个整数hi(1⩽hi⩽n)就是你第i次移动到的房子。对于每个hj(1⩽j⩽k−1)应该满足hj≠hj+1,h1≠1.
输入输出样例
输入 #1

10 2 15

输出 #1

YES
10 4 

输入 #2

10 9 45

输出 #2

YES
10 1 10 1 2 1 2 1 6 

输入 #3

10 9 81

输出 #3

YES
10 1 10 1 10 1 10 1 10 

输入 #4

10 9 82

输出 #4

NO

首先我们判断:s 对于其他情况,一定可以构造,我们每次转移的距离选择s-k和n-1中比较小的那一个,然后总距离减去走的距离,当当前走的距离加上转移的距离大于n的时候,就要往回走,然后一直走下去,就可以构造出来序列了。

#include
using namespace std;
typedef long long ll;
ll n,k,s;
int main()
{
    cin>>n>>k>>s;
    if(s>k*(n-1)||s<k)
    {
        cout<<"NO"<<endl;
        return 0;
    }
    cout<<"YES"<<endl;
    ll now=1;
    while(k--)
    {
        ll dis=min(s-k,n-1);//走路策略是每次尽量走能走的最大值
        s-=dis;
        if(now+dis<=n)
            now+=dis;
        else now-=dis;
        cout<<now<<" ";
    }
    cout<<endl;
    return 0;
}

一.

CF190C STL
题意翻译
给出只会出现pair和int的字符串,要求按照给出pair和intintint的顺序,添加’<’ , ‘>’ 这三个符号,使得给出的串成为一个合法的类型.
输入样例
3
pair pair int int int
输出样例
pair,int>

#include
#include
#include
#include
#include
#include
#include
#define debug cout<<"ok"<
typedef long long ll;
const int maxn=1e4+500;
const int mod=1e9+7;
using namespace std;
string s,buf,ans;
bool flag;
int n;
int init()
{
    if(cin>>s)
    {
        if(s=="pair")//递归是真的秀
        {//只有标准格式才能算对,所以用递归
            ans+="pair<";
            init();
            ans+=",";
            init();
            ans+=">";
        }
        else if(s=="int")
            ans+="int";
    }
    else flag=true;
}
int main()
{
    flag=false;
    ios::sync_with_stdio(false);
    (cin>>n).get();//cin>>n会忽略掉换行符而getline遇见换行符会停止所以cin不能配getline要用(cin>>n).get();代替
    init();
    if(flag)
        ans="Error occurred";
    getline(cin,s);
    if(s.size())
        ans="Error occurred";
    cout<<ans<<endl;
    return 0;
}

二.

P1053篝火晚会
题目概述
一共有n个同学,编号从1到n。一开始,同学们按照1,2,……,n的顺序坐成一圈,实际上每个人都有两个最希望相邻的同学。每一个命令的形式如下:这里m的值是由佳佳决定的,每次命令m的值都可以不同。这个命令的作用是移动编号是b1,b2,…… bm的这m个同学的位置。要求b1换到b2的位置上,b2换到b3的位置上,……,要求bm换到b1的位置上。执行每个命令都需要一些代价。我们假定如果一个命令要移动m个人的位置,那么这个命令的代价就是m。我们需要佳佳用最少的总代价实现同学们的意愿,如果无论怎么调整都不能符合每个同学的愿望,则输出-1。
输入格式
第一行是一个整数n(3≤n≤50000),表示一共有n个同学。
其后n行每行包括2个不同的正整数,以一个空格隔开,分别表示编号是1的同学最希望相邻的两个同学的编号,编号是2的同学最希望相邻的两个同学的编号,……,编号是n的同学最希望相邻的两个同学的编号。
输出格式
一个整数,为最小的总代价。如果无论怎么调整都不能符合每个同学的愿望,则输出−1。
数据规模
3 <= n <= 50000

输入:
4
3 4
4 3
1 2
1 2

输出:
2

思路:总结了一下网上找到的题解,下面给出我自己的理解。首先构造出期望环(这个比较简单),然后跟原环(123…n)比较看有几个不相同的,有几个不同的那么答案就是几。
那么直接比较有几个相同的就知道有几个是不同的了。
假设右移k次是最优解,右移过以后与原数列有t个不同,那交换的代价就是t,那就可以设ans[i]表示右移i位后与原数列有ans[i]个相同, 然后答案即为所有可能中最大的哪一个,然后一共n个减去最大的ans即为所求

求期望环与现在环(即1,2,。。。,n排列)不同的人数,答案就是总人数(n)-不同的人数即可。
判断不同的人数 对于置换得到的数列,找每个数距离初始状态的长,统计相同长的个数即可。

我的答案:

#include
#include
#include
#include
#include
#include
#include
#include
#define debug cout<<"ok"<
typedef long long ll;
const int maxn=1e7+10;
const int mod=1e9+7;
using namespace std;
inline int read()//快读
{
    int x=0,f=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){f|=(ch=='-');ch=getchar();}
    while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48),ch=getchar();}
    return f?-x:x;
}
inline void write(int x)//快写
{
    char f[200];
    int cnt=0,tmp=x>0?x:-x;
    if(x<0)putchar('-');
    while(tmp>0)f[cnt++]=tmp%10+'0',tmp/=10;
    while(cnt>0)putchar(f[--cnt]);
}
int n,a[maxn],b[maxn],h[maxn],ans1[maxn],ans2[maxn],ans;
int main()
{
    n=read();
    for(int i=1;i<=n;i++)a[i]=read(),b[i]=read();
    for(int i=1;i<=n;i++)
        if((a[a[i]]!=i&&b[a[i]]!=i)||(a[b[i]]!=i&&b[b[i]]!=i))//舔狗一无所有
        {
            write(-1);//特判
            return 0;
        }
    h[1]=1;h[n]=a[1];h[2]=b[1];//初始化因为是个环
    for(int i=3;i<=n;i++)//构建期望环
    {
        if(a[h[i-1]]==h[i-2])h[i]=b[h[i-1]];//左边符合就把期望的右边放到现在的右边
        else h[i]=a[h[i-1]];//左边不符合就把期望的左边放到右边(反正是个环)
    }
    for(int i=1;i<=n;i++)
    {
        ans1[(h[i]-i+n)%n]++;//要顺时针走i步的人数
        ans2[(h[i]+i+n)%n]++;//要逆时针走i步的人数
    }
    for(int i=0;i<=n*2;i++)
        ans=max(ans,max(ans1[i],ans2[i]));//取符合人数中的最大值
    write(n-ans);//不符合人数最少即为花费最小代价
    return 0;
}

大佬的思路

你可能感兴趣的:(#,模拟)