CF1517

时间:2021-09-13
本文章向大家介绍CF1517,主要包括CF1517使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

CF1517

B: Morning Jogging

我们只需要把前 \(m\) 小的数放在不同的行中,即可得到最小的疲惫总值。

有个小陷阱就是注意写的时候行和列的顺序。

#include<bits/stdc++.h>
using namespace std;
int T,n,m;
const int N=105,inf=0x3f3f3f3f;
int b[N][N],ans[N][N],l[N],r[N];
int main(){
    cin>>T;
    while(T--){
        cin>>n>>m;
        for(int i=1;i<=n;i++){ 
            for(int j=1;j<=m;j++) scanf("%d",&b[i][j]);
            sort(b[i]+1,b[i]+1+m); 
            l[i]=1,r[i]=m;
        }
        for(int i=1;i<=m;i++){
            int minn=inf,res=0;
            for(int j=1;j<=n;j++) if(b[j][l[j]]<minn) res=j,minn=b[j][l[j]];
            for(int j=1;j<=n;j++){ 
                if(j==res) ans[i][j]=b[j][l[j]++];
                else       ans[i][j]=b[j][r[j]--];
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
                printf("%d ",ans[j][i]);
            puts("");
        }
    }
    // system("pause");
    return 0;
}

C:Fillomino 2

答案唯一存在且每次往左往下走填。

这东西的证明需要另外一种构造方法:

刚开始每种颜色只染对角线上的位置,然后对于 \(pi=1\) 上面的往下染,下面的往左染。染完后所有 \(pi←pi−1\),把上一层涂黑然后递归.

就像这样:

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int a[N],n,ans[N][N];
int main(){
    cin>>n; memset(ans,-1,sizeof(ans));
    for(int i=0;i<n;i++){
        cin>>a[i]; int x=i,y=i;
        for(int j=0;j<a[i];j++){
			ans[x][y]=a[i];
			if(y&&ans[x][y-1]==-1) --y;
			else ++x;
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<i+1;j++) cout<<ans[i][j]<<" ";
        puts("");
    }
    // system("pause");
    return 0;
}

D:Explorer Space

这题读入我看了半天没看懂·····这下智商为 \(0\)

看数据范围,我们肯定不可能暴力算.

考虑分类讨论:

  1. 不能回到原点: \(k\) 是个奇数,当然无法回原点.

  2. 可以回到原点: 其实可以转化成: 走 \(\frac{k}{2}\) 步,求路径长度最小。

考虑 \(dp\), 设 \(f[i][j][d]\) 为从 \((i,j)\) 出发,走了 \(d\) 步的最小取值。

\((x_i,y_i)\) 为与 \((i,j)\) 相连的点,与点 \((i,j)\) 相连的数有 \(m\) 个。

枚举四个方向,得出方程:

\[f[i][j][d]=min^m_1(f[x][y][d-1]) \]
#include <bits/stdc++.h>
using namespace std;
const int N=505;
const int INF=0x3f3f3f3f;
int dedge[N][N];
int redge[N][N];
int ans[N][N],f[N][N][30];//编号为i,j的点在第d步被经过的花费
int n,m,k;
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++) for(int j=1;j<=m-1;j++)
		scanf("%d",&redge[i][j]);
	for(int i=1;i<=n-1;i++) for(int j=1;j<=m;j++)
		scanf("%d",&dedge[i][j]);
	if(k & 1){
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				printf("-1 ");
		printf("\n");
		return 0;
	}
	for(int d=1;d<=(k>>1);d++) // k<<1等价于k/2 
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++){
				f[i][j][d]=INF;
				if(j>1) f[i][j][d]=min(f[i][j][d],f[i][j-1][d-1]+redge[i][j-1]);
                if(j<m) f[i][j][d]=min(f[i][j][d],f[i][j+1][d-1]+redge[i][j]);
                if(i>1) f[i][j][d]=min(f[i][j][d],f[i-1][j][d-1]+dedge[i-1][j]);
                if(i<n) f[i][j][d]=min(f[i][j][d],f[i+1][j][d-1]+dedge[i][j]);
			}
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)
			printf("%d ",f[i][j][k>>1] * 2);
		printf("\n");
	}
    // system("pause");
	return 0;
	
}

E:Group Photo

我们简述一下题意:

对于一个长度为 \(n\) 的序列,每个元素有一个权值 \(a_i\),现在为这个序列染色,每个不是 \(c\) 就是 \(p\) ,且满足:

\[c_i−c_i−1≤c_i+1−c_i \]
\[p_i−p_i−1≥p_i+1−p_i \]

考虑到前两个条件,容易发现只有 \((P)CC...CPCPC...PCPP...P(C)\) 或者 \(PP...PCC...C\) 两种形状满足。

然后的问题就在于要不重复地统计答案。

先看怎么不重复,先假设上面的 \(P\)\(C\)\(PC\) 都可以为空。当前不合法或者重串有:\(PC,PCC...C,PP...PC,P,C\)。发现不允许前面一种形状的 \(PP...P\) 或者 \(CC...C\) 空就可以正好解决这些问题。

具体实现可以维护前缀和、奇偶前缀和然后二分。对于首位 \((P)\)\((C)\) 加不加有 \(4\) 种情况,这可以用一个函数一起解决,具体见代码。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
const int N=2e5+10,mod=998244353;
typedef long long ll;
int n,a[N];
ll s[N],t[N];

int Calc(int i,ll d){
	int ans=0;
	int res=-1;
	for(int l=0,r=(i-1)/2,mid;l<=r;) 
		if(mid=(l+r)>>1,d-t[i]+t[i-mid*2]-s[i-mid*2]>0) r=mid-1,res=mid;
		else l=mid+1;
	if(~res) ans+=(i-1)/2-res+1;
	if(i==1) return ans;
	res=-1;
	for(int l=0,r=(i-2)/2,mid;l<=r;) 
		if(mid=(l+r)>>1,d-t[i]+t[i-mid*2]-s[i-mid*2]+2*a[1]>0) r=mid-1,res=mid;
		else l=mid+1;
	if(~res) ans+=(i-2)/2-res+1;
	return ans;
}

int main(){
    int T; cin>>T;
	while(T--) {
		cin>>n;
		rep(i,1,n) scanf("%d",&a[i]);
		rep(i,1,n) s[i]=s[i-1]+a[i];
		rep(i,1,n) t[i]=a[i]-t[i-1];
		ll ans=0;
		rep(i,1,n-1) {
			ans+=Calc(i,s[n]-s[i]);
			if(i<n-1) ans+=Calc(i,s[n-1]-s[i]-a[n]);
		}
		rep(i,1,n) if(s[i]-(s[n]-s[i])>0) ans++;
		printf("%lld\n",ans%mod);
	}
    // system("pause");
    return 0;
}

原文地址:https://www.cnblogs.com/guanlexiangfan/p/15264607.html