P3558 [POI2013]BAJ-Bytecomputer 学校平台1113数列
posted on 2023-03-09 13:14:33 | under 题集 | source
老师说:此题爆枚比 DP 更重要。
爆枚
我们可以定义两个指针,把一个序列分成三段:-1、0、1。
例如:
a1 a2 | a3 a4 | a5 a6 。
其中,a1 a2 为 -1 段,a3 a4 为 0 段,a5 a6 为 1 段。
只要计算每段的最小代价,加在一起即可。
那么怎么表达类似 -1、1 这样的序列呢?
a1 a2 | | a3 a4 a5 a6 ,其中 a1 a2 为 -1 段,a3 ~ a6 为 1 段。
同理,序列 | | a1 a2 a3 表达的是:a1 ~ a3 为1段。
爆枚做法很有参考价值,时间复杂度为 \(O(n^3)\) 。
贴上我丑陋的代码:b 数组表示修改后的 a 数组,记得判断 每段起点 这种特殊情况。
#include<bits/stdc++.h>
using namespace std;
int n,a[1000005],b[1000005],MAX=1e7,ans;
int change_1(int x)
{
if(x<1) return 0;
int ans=0;
for(int i=1; i<=x;i++)
{
if(a[i]==-1) {b[i]=-1;continue;}
if(i==1&&a[i]!=-1) return -1;
if(a[i]==0) ans++,b[i]=-1;
if(a[i]==1) ans+=2,b[i]=-1;
}
return ans;
}
int change_2(int x,int y)
{
if(x>y) return 0;
int ans=0;
for(int i=x; i<=y;i++)
{
if(a[i]==0) {b[i]=0;continue;}
if(i==x)
{
if(a[i]==1&&b[i-1]==-1) {ans++;b[i]=0;continue;}
return -1;
}
if(a[i]==-1) return -1;
if(a[i]==1) return -1;
}
return ans;
}
int change_3(int x)
{
if(x>n) return 0;
int ans=0;
for(int i=x; i<=n;i++)
{
if(a[i]==1) {b[i]=1;continue;}
if(i==x)
{
if(a[i]==1) {b[i]=1;continue;}
return -1;
}
if(a[i]==-1) ans+=2;
if(a[i]==0) ans++;
}
return ans;
}
int main()
{
cin>>n;
ans=MAX;
for(int i=1; i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=0; i<=n+1;i++)
for(int j=i; j<=n+1;j++)
{
int ans1,ans2,ans3;
ans1=change_1(i);
ans2=change_2(i+1,j);
ans3=change_3(j+1);
if(ans1==-1||ans2==-1||ans3==-1) continue;
ans=min(ans,ans1+ans2+ans3);
}
ans!=MAX?cout<<ans:cout<<"BRAK";
return 0;
}

浙公网安备 33010602011771号