Problem C:
题意;给出序列a,问有多少个区间,其长度在[c,d]并且该区间不包含相同的元素.n,c,d<=1e5.a[i]<=1e9.
双指针 枚举左端点i,维护最远能达到的右端点rg.
Problem D:
题意:给出长度为n的全0序列a.目标序列b.
操作:每次选定一个元素0,假设这个元素为a[i].
若a[i-1],a[i+1]都不为1,则a[i]变为1.
若a[i-1],a[i+1]至少一个为1,但是都不为2,则a[i]=2并且相邻为1的变为0.
若a[i-1],a[i+1]一个为1,一个为2,则a[i]变为3 其邻居都变为0.
n<=1e5,问将序列a变为序列b的最少操作次数? 并输出方案.
模拟题,相邻元素不能相同,变一个3需要4步.核心:因为变3后回清0旁边,变2后会清零1.所以操作数和操作次序是固定的.
题意;给出序列a,问有多少个区间,其长度在[c,d]并且该区间不包含相同的元素.n,c,d<=1e5.a[i]<=1e9.
双指针 枚举左端点i,维护最远能达到的右端点rg.
则左端点为i的合法区间最长为rg-i+1,所以贡献为max(0,min(rg-i+1,d)-c+1)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20;
int n,a[N];
map<int,int> mp;
int main()
{
int c,d;
cin>>n>>c>>d;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int rg=1;
ll ans=0;
for(int i=1;i<=n;i++)
{
while(rg<=n)
{
if(!mp[a[rg]])
mp[a[rg]]++,rg++;
else
break;
}
// cout<<i<<' '<<rg-1<<endl;
int len=rg-i;
mp[a[i]]--;
ans+=max(0,min(len,d)-c+1);
}
cout<<ans<<endl;
return 0;
}
Problem D:
题意:给出长度为n的全0序列a.目标序列b.
操作:每次选定一个元素0,假设这个元素为a[i].
若a[i-1],a[i+1]都不为1,则a[i]变为1.
若a[i-1],a[i+1]至少一个为1,但是都不为2,则a[i]=2并且相邻为1的变为0.
若a[i-1],a[i+1]一个为1,一个为2,则a[i]变为3 其邻居都变为0.
n<=1e5,问将序列a变为序列b的最少操作次数? 并输出方案.
模拟题,相邻元素不能相同,变一个3需要4步.核心:因为变3后回清0旁边,变2后会清零1.所以操作数和操作次序是固定的.
先变3然后变2然后再变1,如果某步无法变化 则说明无解.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20;
int n,a[N],res[N],sz=0;
void fail()
{
printf("-1\n");
exit(0);
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=1;i<n;i++)
if(a[i]==a[i-1]&&a[i])
fail();
if(a[0]==3||a[n-1]==3)
fail();
for(int i=0;i<n;i++)
{
if(a[i]==3)
{
res[sz++]=i;
res[sz++]=i-1;
res[sz++]=i+1;
res[sz++]=i;
}
}
for(int i=0;i<n;i++)
{
if(a[i]==2)
{
if(i&&a[i-1]!=3)
res[sz++]=i-1,res[sz++]=i;
else if(i+1<n&&a[i+1]!=3)
res[sz++]=i+1,res[sz++]=i;
else
fail();
}
}
for(int i=0;i<n;i++)
if(a[i]==1)
res[sz++]=i;
printf("%d\n",sz);
for(int i=0;i<sz;i++)
printf("%d ",res[i]+1);
return 0;
}
Problem E:
题意:n*m地图,电脑初始在左上角(1,1),每次可以向下或者向右,终点为右下角(n,m),
有k个格子是特殊的,电脑走的路径会尽量经过最多的特殊格子,假设最多只能经过best个特殊格子.
现在问这k个格子中有多少个是关键的,也就是说把这个格子变成不特殊后,best一定会减小.
n,m<=1e9,k<=1e5.
经典的LIS变形,每一步坐标的x,y都是非递减的.
将k个点按行从小到大排序,这此时列作为序列a的元素,则best就等于序列a的LIS长度.
critical cell就是出现在所有LIS中的元素.
序列a的LIS长度记为opt
设r[i],l[i]为以i结尾和以i开头的的LIS长度 如果r[i]+l[i]-1=opt则说明a[i]出现在某个LIS中.
假如i,j属于某个lis,并且l[i]=l[j].则a[i],a[j]肯定不会同时出现在一个LIS中.
假如同时出现 若a[i]在a[j]之前 则l[j]=l[i]+1矛盾, 若a[i]在a[j]之后则l[j]+1+r[i]>opt矛盾.
即cnt[x]>1,则说明l[i]=x的i都是不必要点 由逆否命题得cnt[x]==1的为必要点.
#include <bits/stdc++.h>
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20;
int row,col,n,d1[N],d2[N],cnt[N];
ii a[N];
vector<int> lis;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>row>>col>>n;
for(int i=0;i<n;i++)
cin>>a[i].F>>a[i].S;
sort(a,a+n);
for(int i=0;i<n;i++)
{
int pos=upper_bound(lis.begin(),lis.end(),a[i].S)-lis.begin();
d1[i]=pos+1;
if(pos==lis.size())
lis.push_back(a[i].S);
else
lis[pos]=a[i].S;
}
lis.clear();
for(int i=n-1;i>=0;i--)
{
int pos=upper_bound(lis.begin(),lis.end(),-a[i].S)-lis.begin();
d2[i]=pos+1;
if(pos==lis.size())
lis.push_back(-a[i].S);
else
lis[pos]=-a[i].S;
}
int mx=lis.size(),ans=0;
for(int i=0;i<n;i++)
{
if(d1[i]+d2[i]-1==mx)
cnt[d1[i]]++;
}
for(int i=1;i<N;i++)
if(cnt[i]==1)
ans++;
cout<<ans<<endl;
return 0;
}