CF1821A Matching
题意:给一个带问号的数,问有多少个数可以和它相匹配。
思路:统计有多少个问号,每一个问号,答案*10,特判一下最高位为问号则/10*9,另外还需要特判一下前置零的情况。
#include<bits/stdc++.h>
using namespace std;
int t,ans,pos;//sum表示问号的个数,pos表示问号在不在最高位
char s[10];
int main()
{
cin>>t;
while(t--)
{
cin>>s;
pos=0; ans=1;
int n=strlen(s);
if(s[0]=='0') //前置零
{
cout<<"0\n";
continue;
}
if(s[0]=='?')
{
ans*=10; pos=1;
}
for(int i=1;i<n;i++)
{
if(s[i]=='?') ans*=10;
}
if(pos==1) ans=ans/10*9;
cout<<ans<<"\n";
}
return 0;
}
CF1821B Sort the Subarray
题意:给定数组a和a’,求最大的位置l,r,使得a[l]至a[r]以内的数排序后,a数组和a‘数组相同
思路:
1.队友思路:从左往右找不同,得l,从右往左找不同,得r,然后l向左扩展,r向右扩展(应该是非常正确的正解)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=200000+100;
int n,a[N],b[N];
int l,r;
void work();
int main()
{
int T; scanf("%d",&T);
while(T--)
{
work();
}
return 0;
}
void work()
{
scanf("%d",&n); l=-1;r=-1;
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
for(int i=1; i<=n; i++) scanf("%d",&b[i]);
for(int i=1; i<=n; i++)
{
if(b[i]!=a[i])
{
l=i;
break;
}
}
for(int i=n; i>=1; i--)
{
if(b[i]!=a[i])
{
r=i;
break;
}
}
while(l>1)
{
if(b[l-1]<=b[l]) l--;
else break;
}
while(r<n)
{
if(b[r+1]>=b[r]) r++;
else break;
}
printf("%d %d\n",l,r);
}
2.我的思路:在左右找到不同之前,维护两个单调不减的子串(其实从本质上都是一样的)
#include<bits/stdc++.h>
using namespace std;
int t,n,minn,maxn,l,r,a[200010],b[200010];
int main()
{
cin>>t;
while(t--)
{
cin>>n;
minn=100000000; maxn=0;
l=0; r=100000000;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++)
{
if(a[i]==b[i])
{
if(a[i]<minn)
{
l=i; minn=a[i];
}
else minn=a[i];
}
else
{
if(i==1)
{
l=1; break;
}
if(b[i]<b[i-1]) l=i;
break;
}
}
for(int i=n;i>=1;i--)
{
if(a[i]==b[i])
{
if(a[i]>maxn)
{
r=i; maxn=a[i];
}
else maxn=a[i];
}
else
{
if(i==n)
{
r=i; break;
}
if(b[i]>b[i+1]) r=i;
break;
}
}
cout<<l<<" "<<r<<"\n";
}
return 0;
}
注:其实这两种方法没有本质的区别,但是我想的时候没有深入(想到正解就开写了,没有去想怎么化简好一点),这样其实不太好,CF的比赛时间比较短,如果解法过于复杂会浪费蛮多时间。
CF1821C Tear It Apart
题意:给定一个字符串,可以进行若干次操作,每一次操作可以删掉若干个不相邻位置的字符,问最少需要多少次操作,可以使该串只剩一种字母。
思路:蛮简单的一个贪心,细细地试一下样例就可以明白,就是要找最小的同一字符间的最大间隔。
#include<bits/stdc++.h>
using namespace std;
int t,n,sum,pre,ans,sum2;
char s[200010];
int main()
{
cin>>t;
while(t--)
{
cin>>s; ans=0;
n=strlen(s); sum=0; sum2=10000000000;
for(int k=1;k<=26;k++)
{
sum=0;
pre=0;
for(int i=0;i<n;i++)
{
int now=s[i]-'a'+1;
if(now==k)
{
if(pre==0)
{
pre=i+1;
sum=max(sum,i);
}
else
{
sum=max(sum,i+1-pre-1);
pre=i+1;
}
}
if(i==n-1&&now!=k)
{
sum=max(sum,n-pre);
}
}
sum2=min(sum2,sum);
}
while(sum2)
{
ans++;
sum2/=2;
}
cout<<ans<<"\n";
}
return 0;
}
注:题目其实蛮简单,但是感觉自己代码实现得有点垃圾,还是感觉写复杂了,影响做题速度。
CF1821D Black Cells
思路:本质上来说,这也是一个贪心。首先,必然的是,一个区间的长度大于1时,那我们一定会把这个区间涂黑。对于长度为1的区间,如果最后一个区间还没涂完,我们一定会去涂最后一个区间而不涂长度为1的区间,如果最后一个区间也涂满了,还没有达到k,此时我们再考虑涂长度为1的区间。重要的是状态设定。我们遍历所有的区间,对于第i个区间,把它当成答案的最后一个区间,然后按照确定的优先级来选择区间(达到k就停止)1.选择1~i-1之间长度大于1的区间 2.选择涂第i个区间 3.选择涂i前面的长度为1的区间。
#define ll long long
#include<bits/stdc++.h>
using namespace std;
ll t,n,k,cnt,sum,ans=100000000000,l[300010],r[300010];
int main()
{
cin>>t;
while(t--)
{
cin>>n>>k; cnt=0; ans=100000000000; sum=0; cnt=0;
for(int i=1;i<=n;i++) cin>>l[i];
for(int i=1;i<=n;i++) cin>>r[i];
for(int i=1;i<=n;i++)
{
ll len=r[i]-l[i]+1;
sum+=len;
if(sum>=k&&sum-cnt-len<k)
{
if(sum-cnt>=k)//如果在最后一个区间里面选就可以大于K,就不用选长度为1的了
{
ans=min(ans,(i-cnt)*2+l[i]+(k-(sum-len-cnt))-1);
}
else//选长度为1的
{
ans=min(ans,(i-cnt)*2+r[i]+2*(k-(sum-cnt)));
}
}
if(len==1)
{
cnt++;
}
}
if(ans==100000000000) cout<<"-1\n";
else cout<<ans<<"\n";
}
return 0;
}
注:其实今天上午思路出的还是比较快,调试的时候主要是表达式有些时候没注意写错了,下次应该先在纸上把每个表达式写好再打上去