P9572 Colorful Days♪
思路
Step0.骗分
显然,题目中的
Step1.暴力不出奇迹
显然第一个想到的是暴力,枚举
但是非常显然,这样时间复杂度及其高,定然会 TLE。
Step2.观察性质
我们发现,如果
Step3.从模拟入手
想要直接找到最小
因为我们在 Step2 中得出结论,只要是同时存在于数组
假设当前遍历到的数是
如果
如果
这样就完美地解决了
Step4.代码写法
可以用 vector 储存每个数字在数组
用一个变量,储存上一个可贡献答案的数在数组
我们就只需要遍历 vector,找到位置之后的满足条件的坐标,如果找不到,就增加
AC 代码
#include<bits/stdc++.h>
using namespace std;
int n,m,c1,c2,s[1000005],t[1000005],res,k=1,p,cnt;
vector<int>v[1000005];
int main()
{
scanf("%d%d%d%d",&n,&m,&c1,&c2);
for(int i=1;i<=n;++i) scanf("%d",&s[i]),v[s[i]].push_back(i);
for(int i=1;i<=m;++i) scanf("%d",&t[i]);
for(int i=1;i<=m;++i)
{
if(!v[t[i]].size()) continue;//如果在S中不存在就直接跳过
else
{
int flag=0;res++;//用flag标记是否找到位置
for(int j=0;j<v[t[i]].size();++j) if(v[t[i]][j]>p){flag=1,p=v[t[i]][j];break;}//找到第一个大于p的位置
if(!flag) k++,p=v[t[i]][0];//没找到就需要增加k了,记得赋值
}
}
printf("%d %d",res*c1,k*c2);//别忘了乘以c1,c2
return 0;
}
题外话
这个代码其实有个小问题,如果 LCS 为
改代码也很简单,只需要判断 这里不改是看看到时候会不会有人直接复制交(滑稽)。
Step5.进一步的优化
原本交了,但是被巨佬同学说了,我这个复杂度过了是因为数据水,所以我有屁颠屁颠地跑回来修改了。
显然如果数据构造合适,在查找位置的时候会被卡,所以考虑在查找优化时间复杂度,第一时间就想到是二分。绝对不是看到标签里有二分。
这样的话就容易了,只需要再写个二分查找就好了。
仅贴出部分代码(二分查找函数和调用部分的循环代码)
int find(int i,int x)
{
int l=0,r=v[i].size()-1,mid,ans=-1;
while(l<=r)
{
mid=l+r>>1;
if(v[i][mid]>x) r=mid-1,ans=v[i][mid];
else l=mid+1;
}
return ans;
}
/////////////
for(int i=1;i<=m;++i)
{
if(!v[t[i]].size()) continue;
else
{
int l=find(t[i],p);res++;
if(l==-1) k++,p=v[t[i]][0];
else p=l;
}
}