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-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 imes 500 imes 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
",ans);
}
推荐
(AcWing 274)
总结
开数组一定要开的正好,要计算空间复杂度,考虑要全面.
惨痛的教训
( ext{相较于丢失你,我更怕的是丢失自我。我想做你眼中站立的影子,不愿摇尾乞怜的拥抱,我愿自爱})