0920 模拟赛

T1

链接

Idea

在考场上打了暴力后,发现了一个规律:
\(n\)为奇数时,\(ans=min\{a\}-1\),当\(n\)为偶数时,\(ans=0\)
但,只有\(80pts\)ts.png
我发现\(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,我太菜了lb.png
现在看来,这是一个很明显的构造题
在想这道题之前,我们来思考几个问题
\(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\)的数组lb.png

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\)

总结

开数组一定要开的正好,要计算空间复杂度,考虑要全面.
惨痛的教训ll.png
\(\text{相较于丢失你,我更怕的是丢失自我。我想做你眼中站立的影子,不愿摇尾乞怜的拥抱,我愿自爱}\)

posted @ 2019-09-21 08:32  云山乱  阅读(194)  评论(0编辑  收藏  举报