寒假集训-1.27
Educational Codeforces Round 91 (Rated for Div. 2)
https://codeforces.com/contest/1380
A - Three Indices
思路
A题做的一头雾水,我感觉我的代码好复杂。
每一个位置前面数的最小值和后面数的最小值求出来,遍历一下查看一下是否存在同时大于两边最小值的数,如果不存在则输出-1,存在就把两个最小值保存下来,再次遍历得到下标。
Code
#include<bits/stdc++.h>
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int inf=0x3f3f3f3f;
typedef long long ll;
const int N=200000;
const ll mod=1e9+7;
int a[1007],b[N],c[N];
int main(){
IO;
int t=1;
cin>>t;
while(t--){
int n;
cin>>n;
for (int i = 1; i <= n; ++i)
{
cin>>a[i];
}b[1]=c[n]=inf;
for (int i = 2; i < n; ++i)
{
b[i]=min(b[i-1],a[i-1]);
}
for (int i = n-1; i > 1; --i)
{
c[i]=min(c[i+1],a[i+1]);
}int x=0,y=0,z=0,flag=0;
for (int i = 2; i < n; ++i)
{
if(a[i]>b[i]&&a[i]>c[i]){
flag=i;
break;
}
}if(!flag)cout<<"NO"<<endl;
else{
cout<<"YES"<<endl;
for (int i = 1; i <= n; ++i)
{
if(!x&&a[i]==b[flag]&&i!=flag&&i!=y)x=i;
if(!y&&a[i]==c[flag]&&i!=flag&&i!=x)y=i;
}cout<<x<<" "<<flag<<" "<<y<<endl;
}
}
return 0;
}
B - Universal Solution
思路
因为题目中说要在任意位置开始并且玩n盘,只要保证对于出现次数最多的选项我们获胜即可,这样就可以保证我们的胜场总数量最大化。
所以直接搜一遍找到出现次数最多的,假如是R,我们只需要全出P,这样无论从哪个位置开始我们平均下来永远是最优的。
Code
#include<bits/stdc++.h>
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int inf=0x3f3f3f3f;
typedef long long ll;
const int N=200000;
const ll mod=1e9+7;
int main(){
IO;
int t=1;
cin>>t;
while(t--){
string x;
cin>>x;
int r=0,s=0,p=0;
int n=int(x.size());
for (int i = 0; i < n; ++i)
{
if(x[i]=='R')r++;
else if(x[i]=='P')p++;
else s++;
}
int k=max(r,max(s,p));
char y;
if(k==r)
y='P';
if(k==s)
y='R';
if(k==p)
y='S';
while(n--)cout<<y;
cout<<endl;
}
return 0;
}
C - Create The Teams
思路
题目要求得出最大的分组数,并且每组的人数与最小值的乘积必须大于等于x。
因为组内的最小值会影响组的人数,所以先排序然后从大到小选数。
大于等于x的值独立分成一队是最优的,遇到小于x的值就一直将比它小的值加进去直到满足条件就接着进行下一组的分配。
Code
#include<bits/stdc++.h>
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int inf=0x3f3f3f3f;
typedef long long ll;
const int N=1e5+7;
const ll mod=1e9+7;
int a[N];
bool cmp(int x,int y){return x>y;}
int main(){
IO;
int t=1;
cin>>t;
while(t--){
int n,x;
cin>>n>>x;
for (int i = 1; i <= n; ++i)
{
cin>>a[i];
}
sort(a+1,a+1+n,cmp);
int ans=0;
for (int i = 1; i <= n; )
{
if(a[i]>=x){
ans++;
i++;
continue;
}
int cnt=1;
while(i<=n&&cnt*a[i]<x){
cnt++;
i++;
}
if(i>n)break;
ans++;
i++;
}cout<<ans<<endl;
}
return 0;
}
D - Berserk And Fireball
思路
题目大意是给出一排战士的战斗力值,你可以通过两种方式进行对战士的消灭:
-1.花费x法力消灭连续的k个战士
-2.花费y法力选定连续的2个战士,此操作会消除战斗力小的战士。
求将给出的战士序列a变成战士序列b的花费的最小法力值。
我们需要按b序列将a序列依次划分成多个区间,只能在区间内进行操作(无法修改区间端点)
首先考虑不可能的情况:
-1.两个序列长度相同,但是在b中先后顺序与a中不同则无法操作。
-2.区间内存在大于区间端点的值,但是区间长度(不包括端点,因为端点不能删除)小于k,此时无法处理大于端点的值。
在处理区间内的值时,需要判断直接消去k个值花费小还是使用单个消除的方法花费小。这里需要特判一下是否存在大于区间端点的值,如果区间极大值在区间内,则必须先使用一次方法1,因为方法2无法删去此极大值。
Code
#include<bits/stdc++.h>
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int inf=0x3f3f3f3f;
typedef long long ll;
const int N=2e5+7;
const ll mod=1e9+7;
ll a[N],b[N];
ll ans=0;
int maxn;
ll n,m,x,k,y;
ll slove(ll l,ll r){
ll cnt=r-l-1ll;
ll res=0,p=0;
for (int i = l+1; i < r; ++i)
{
if(a[i]>a[l]&&a[i]>a[r])p++;
}
if(p&&cnt<k)return -1;
if(p){
res+=x;
cnt-=k;
}
if(x<=k*y){
p=cnt/k;
res+=p*x;
cnt-=p*k;
}
res+=cnt*y;
return res;
}
int main(){
IO;
int t=1;
//cin>>t;
while(t--){
cin>>n>>m;
cin>>x>>k>>y;
int flag=1;
map<ll,int>mp;
for (int i = 1; i <= n; ++i)
{
cin>>a[i];
}a[n+1]=0;
for (int i = 1; i <= m; ++i)
{
cin>>b[i];
mp[b[i]]=1;
if(i<=n)
if(a[i]!=b[i])
flag=0;
}
if(n<m||(n==m&&!flag))cout<<"-1"<<endl;
else if(n==m&&flag)cout<<0<<endl;
else{
flag=1;
ans=0;
for (int i = 1; i <= n; ++i)
{
if(mp[a[i]])mp[a[i]]=i;
}
for (int i = 2; i <= m; ++i)
{
if(mp[b[i-1]]>mp[b[i]]){
flag=0;
break;
}
}if(!flag)cout<<-1<<endl;
else{
if(mp[b[1]]!=1){
ll sum=slove(0ll,mp[b[1]]);
if(sum==-1)flag=0;
else ans+=sum;
}
if(mp[b[m]]!=n){
ll sum=slove(mp[b[m]],n+1ll);
if(sum==-1)flag=0;
else ans+=sum;
}
for (int i = 1; i < m; ++i)
{
ll sum=slove(mp[b[i]],mp[b[i+1]]);
if(sum==-1){
flag=0;
break;
} ans+=sum;
}cout<<((flag==0)?-1:ans)<<endl;
}
}
}
return 0;
}
!!!加油
Code will change the world !

浙公网安备 33010602011771号