有一些难度的模拟题
走路模拟器
题意翻译
题目描述
在一条路上,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<ks<k时一定构造不出来k∗(n−1)<sk∗(n−1)<s时也构造不出来
对于其他情况,一定可以构造,我们每次转移的距离选择s-k和n-1中比较小的那一个,然后总距离减去走的距离,当当前走的距离加上转移的距离大于n的时候,就要往回走,然后一直走下去,就可以构造出来序列了。
#include<bits/stdc++.h>
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<pair<int,int>,int>
#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<cmath>
#define debug cout<<"ok"<<endl
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<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<cmath>
#include<deque>
#define debug cout<<"ok"<<endl
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;
}