NOIP模拟八
这一场比之前的要好一些,能拿得分多一些,珂惜T1挂了……
不过全是原题是什么鬼?出题人原神玩多了?
link
T1
先考虑直接暴力去匹配,如果快要超出 就跳回开头,答案加一。但是这样很容易被卡成 ,我们考虑记录下 中每个字符第一个出现位置和最后一个出现位置,如果匹配的时候当前位置大于要匹配的字符最后出现的位置,那么就直接跳到第一个出现的位置重新匹配,不过要加一要不然这个位置会被相同字符匹配两次,别问我怎么知道的……
code
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=114514,M=1919810;
string s,t;
ll num[27],ans,first[27],last[27];
int main(){
cin>>s>>t;
for(int i=0;i<26;++i) first[i]=-1;
for(int i=0;i<s.size();++i){
++num[s[i]-'a'];
if(first[s[i]-'a']==-1) first[s[i]-'a']=i;
last[s[i]-'a']=i;
}
ll pos=0;
for(int i=0;i<t.size();++i){
if(!num[t[i]-'a']){
cout<<-1;
return 0;
}
for(int j=pos;j<s.size();++j){
if(j>last[t[i]-'a']){
pos=first[t[i+1]-'a']+1,++ans;
//不加1寄了…………………………
break;
}
if(s[j]==t[i]){
pos=j+1;
break;
}
if(j==s.size()-1) j=first[t[i]-'a']-1,++ans;
}
if(pos==s.size()&&i<t.size()-1) pos=first[t[i+1]-'a'],++ans;
}
cout<<ans+1;
return 0;
}
T2
思维题,贪心,二分查找(有但并没有用到)。go to learn how to use binary search
我们首先把原序列的重心找到记作 ,将问题转换成求最小的 。我们希望得到每移动一次之后对应的最小值的区间,设为 ,珂以发现 ,我们希望每次移动的时候都能取到最优的区间,但是因为我们是从两端删减元素的,所以每一步我们都珂以贪心地找到最小差值对应的区间。
于是我们可以预处理前缀和来快速处理差值,然后把他们用pair或者结构体放在一起,升序排列,然后算最小答案时维护较大/较小一维的后缀和就可以了。
code
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lb long double
#define mk make_pair
const ll N=2*114514,M=1919810;
const lb inf=114514191981000.0;
ll n,a[N],l,r;
lb ans=inf,mid,sum[N];
lb getmid(ll l,ll r){
return (sum[r]-sum[l-1])*1.0/(r-l+1);
}
typedef pair <lb,lb> pi;
pi res[N];
int main(){
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i],sum[i]=sum[i-1]+a[i];
mid=sum[n]*1.0/n,l=1,r=n;
for(int i=1;i<n;++i){
++l;
if(getmid(l-1,r-1)>mid) --l,--r;
res[i]=mk(getmid(l,r),getmid(l-1,r-1));
}
sort(res+1,res+n);
lb mi=mid;
for(int i=n-1;i>=1;--i) ans=min(ans,res[i].first-mi),mi=min(mi,res[i].second);
printf("%.12Lf",min(ans,abs(mi-mid)));
return 0;
}
T3
思维题,人类智慧。
T4
思维题,圆方树?就你叫NOIP模拟赛?
頑張って