0920 模拟赛
T1
Idea
在考场上打了暴力后,发现了一个规律:
当\(n\)为奇数时,\(ans=min\{a\}-1\),当\(n\)为偶数时,\(ans=0\)
但,只有\(80pts\)
我发现\(ans=min\{a_i-1\},i\%2=1\)
所以
Code
int n=read();
for(int i=1;i<=n;i++) a[i]=read();
if(n&1){
for(int i=1;i<=n;i++)
if(i&1)minn=min(minn,a[i]-1);
printf("%d",minn);
}
else puts("0");
T2
Idea
考场上没写出来,QAQ,我太菜了
现在看来,这是一个很明显的构造题
在想这道题之前,我们来思考几个问题
\(Q:\)把一个序列改成单调不下降的序列,至少需要修改多少个数?
\(A;ans=len-len_{LIS}\)
\(Q:\)把一个序列改成单调递增的序列,至少修要修改几个数?
\(A:\)构造序列\(b[i]=a[i]-1\),\(ans=len-len_{LIS_b}\)
\(Why?\) 因为要求严格单调递增,所以前一项与后一项至少相差一,将这个必要的差值减去
就相当于求\(B\)改成非严格单增最少需修改的数,也就相当于上一个问题
现在本题要求把序列改成一个单调递增的正整数序列
那求的就是:首项为非负整数的最长上升子序列
Code
int a[maxn],b[maxn],f[maxn],len,n;
inline int find(int x){
int l=1,r=len+1;
if(x<f[1]) return 0;
while(l+1<r){
int mid=l+r>>1;
if(f[mid]<=x) l=mid;
else r=mid;
}
return l;
}
inline void solve(){
len=0;
for(int i=1;i<=n;i++){
if(b[i]<0) continue;
int mid=find(b[i]);
len=max(mid+1,len);
f[mid+1]=min(f[mid+1],b[i]);
}
printf("%d\n",n-len);
}
signed main(){
int T=read();
while(T--){
n=read();
memset(f,0x3f,sizeof f);
for(int i=1;i<=n;i++){
a[i]=read();
b[i]=a[i]-i;
}
solve();
}
return 0;
}
推荐
可以写写\(CF13C Sequence,POJ3666\)
T3
Idea
这道题是写出来了,但是\(MLE\)了
这是一道\(DP\)
\(f[i][x][y][z]\) 代表为第i次选择的情况下,对应的1,2,3号服务员
所对应的位置
那么可以得知
\(f[i][p[i]][y][z] = min(f[i][p[i]][y][z], f[i - 1][x][y][z] + c[x][p[i]])\)
\(f[i][x][p[i]][z] = min(f[i][x][p[i]][z], f[i - 1][x][y][z] + c[y][p[i]])\)
\(f[i][x][y][p[i]] = min(f[i][x][y][p[i]], f[i - 1][x][y][z] + c[z][p[i]])\)
因为肯定有一个位置,继承了上一个的位置
所以保存两个状态就可以了
三种状态转移 \(p_i,x,y\)
\(f[i][x][y] = min(f[i][x][y], f[i - 1][x][y] + c[pi - 1][pi])\)
\(f[i][pi][y] = min(f[i][pi][y], f[i - 1][x][y] + c[x][pi])\)
\(f[i][x][pi] = min(f[i][x][pi], f[i - 1][x][y] + c[y][pi])\)
我\(sb\)的开了\(500 \times 500 \times 500\)的数组
Code
和上面的状态不同哦
int T=read();
while(T--){
int n=read(),l=read();
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
c[i][j]=read();
p[0]=3;
for(int i=1;i<=l;i++) p[i]=read();
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(c[i][j]>c[i][k]+c[k][j])
c[i][j]=c[i][k]+c[k][j];
f[0][1][2]=0;
for(int i=0;i<=l;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++){
f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]+c[p[i]][p[i+1]]);
f[i+1][p[i]][k]=min(f[i+1][p[i]][k],f[i][j][k]+c[j][p[i+1]]);
f[i+1][j][p[i]]=min(f[i+1][j][p[i]],f[i][j][k]+c[k][p[i+1]]);
}
int ans=inf;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(i==j) continue;
if(f[l][i][j]<ans) ans=f[l][i][j];
}
printf("%d\n",ans);
}
推荐
\(AcWing 274\)
总结
开数组一定要开的正好,要计算空间复杂度,考虑要全面.
惨痛的教训
\(\text{相较于丢失你,我更怕的是丢失自我。我想做你眼中站立的影子,不愿摇尾乞怜的拥抱,我愿自爱}\)