题意
n个学生坐一排,每个学生要么朝左要么朝右
每秒钟可以将当前状态的任意几对面对面的相邻学生往自己的反方向转动
要求恰好在k秒钟之后保证没有任何一对相邻学生面对面
问是否存在解决方案
解题思路
首先可以想到(猜到)的是,如果刚开始已经没有任何一对相邻学生面对面了
那就直接输出-1
否则一定存在解决方案
且解决方案的秒数范围为:
每秒钟把所有相邻且面对面的学生反向,可以得到最少的时间mink
每秒钟只让一对相邻且面对面的学生反向,可以得到最多的时间maxk
只要mink<=k<=maxk
,则存在解决方案
当然,在取maxk的过程中不能随意选一对学生改变(最好不要),而是按照取mink的过程的先后顺序,把多对学生拆解成一对对再进行改变
所以先是模拟和预处理,每次搜索一遍当前状态,如果检测到 x 对相邻学生面对面,则让maxk+=x,mink+=1
直到x==0
(得到答案)或者mink>k
(要求步数太少,不存在方案)时,退出模拟
然后就开始处理答案(贪心,让时间变得更多)
我们让kk=mink
,以kk<k
作为循环条件
比如在取mink的过程中某一秒交换了5对学生
那么最多就可以把这5对分成5秒进行交换
所以只要在mink过程中的某一秒交换的学生没有用完,就可以让kk+=1,表示我们又浪费了一秒钟(又拓展出了一秒钟使得这个解决方案更接近要求的k)
如果在某次输出后,这一过程中交换的学生对全部用完了,先kk+=1,又因为用完也就表示实际上少了一秒的过程,kk-=1,中和一下,什么也没发生……所以这里特殊处理下
在最后满足kk==k
时,就可以把剩下的没有输出完的按照mink的过程一秒为一组全部输出
程序
用vector储存取mink时每一秒钟交换的位置
(405ms/2000ms)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,k;
ll maxk=0,mink=0,d;
char str[3050];
vector<int> v[3000050];
void solve()
{
int p=0,p2=0,kk=mink;
while(kk<k)//k与mink之间的差值就是要增加的秒数
{
cout<<"1 "<<v[p][p2]<<'
';//前面每秒交换一对就行
p2++;
if(p2==v[p].size())//第p秒的所有学生对都已经交换完的话
{
p2=0;
p++;//换至下一秒
}
else
kk++;//否则让kk+1
}
cout<<v[p].size()-p2;//特殊处理中间这一个,经过上面的每秒一人处理后,第p秒还剩下size-p2个学生没有处理
for(int i=p2;i<v[p].size();i++)//接下来让剩下的全部输出
cout<<' '<<v[p][i];
cout<<'
';
p++;//第p秒处理完了,切换至下一秒
while(p<mink)//只要p<mink,则接下来每一秒就按照取mink时的过程全部输出
{
cout<<v[p].size();
for(int i=0;i<v[p].size();i++)
cout<<' '<<v[p][i];
cout<<'
';
p++;
}
}
void check(int p)
{
for(int i=1;i<n;)
{
if(str[i]=='R'&&str[i+1]=='L')
{
str[i]='L';
str[i+1]='R';//更新
v[p].push_back(i);
i+=2;
}
else
i++;
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>k>>(str+1);
check(0);//下标从0开始
while(v[mink].size()&&mink<=k)//如果还有面对面的学生,并且mink不大于给定的k时,继续执行
{
maxk+=v[mink].size();//最多次数加上size
mink++;//最少次数加1
check(mink);
}
if(mink<=k&&k<=maxk)//给定的k在范围内的话就处理输出
solve();
else
cout<<"-1
";
return 0;
}