暑假集訓CSP提高模擬17

_君の名は發表於2024-08-13

A. 符號化方法初探

看最大數和最小數的絕對值大小,用至多 \(n-1\) 次讓其符號相同,是正數就加前一個數,是負數就倒著加後一個數,最多

\(n-2\) 次。

點選檢視程式碼
#include<bits/stdc++.h>
const int maxn=2e5+10;
using namespace std;
int n,a[maxn],x[maxn],y[maxn],cnt,minn,maxx,ma,mi; 

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	maxx=-2e9;
	minn=2e9;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(a[i]>maxx) maxx=a[i],ma=i;
		if(a[i]<minn) minn=a[i],mi=i;
	}
	if(-minn>maxx)
	{
		for(int i=1;i<=n;i++)
		{
			if(a[i]>0)
			{
//				a[i]+=minn;
				x[++cnt]=mi,y[cnt]=i;
			}
		}
		for(int i=n-1;i>=1;i--)
		{
//			a[i]+=a[i+1];
			x[++cnt]=i+1,y[cnt]=i; 
		}
	}
	else
	{
		for(int i=1;i<=n;i++)
		{
			if(a[i]<0)
			{
//				a[i]+=maxx;
				x[++cnt]=ma,y[cnt]=i;
			}
		}
		for(int i=2;i<=n;i++)
		{
//			a[i]+=a[i-1];
			x[++cnt]=i-1,y[cnt]=i; 
		}
	}
	cout<<cnt<<'\n';
	for(int i=1;i<=cnt;i++)cout<<x[i]<<" "<<y[i]<<'\n';
	
	return 0;
}
/*
4
-1 -1 0 -1
*/

B. 無標號 Sequence 構造

思維題,\(n^3\) 暴力肯定不行,但他只問相不相等,所以我們可以構造一個 \(1*n\) 的矩陣,由於矩陣乘法滿足結合率,所以

我們先 \(n^2\) 讓等號兩邊矩陣都乘上構造矩陣再 \(n^2\) 判等即可

點選檢視程式碼
#include<bits/stdc++.h>
const int mod=998244353;
const int maxn=3010;
using namespace std;
int t,n,a[maxn][maxn],b[maxn][maxn],c[maxn][maxn],flag,aa[2][maxn],cc[2][maxn];

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>t;
	while(t--)
	{
		flag=0;
		cin>>n;
		memset(aa,0,sizeof aa);
		memset(cc,0,sizeof cc);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)cin>>a[i][j];
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)cin>>b[i][j];
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)cin>>c[i][j];	
		
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				aa[1][i]=(aa[1][i]+1ll*a[j][i]*(j%2+1)%mod)%mod;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				cc[1][i]=(cc[1][i]+1ll*c[j][i]*(j%2+1)%mod)%mod;	
		for(int i=1;i<=n;i++)
		{
			long long temp=0;
			for(int j=1;j<=n;j++)
	    	{
	    		temp=(temp+1ll*aa[1][j]*b[j][i])%mod;
//	    		cout<<temp<<" "<<cc[1][i]<<endl;
			}
			if(temp!=cc[1][i])flag=1;
			if(flag)break;
		}		
		if(flag) cout<<"No"<<'\n';
		else cout<<"Yes"<<'\n';
	}
	
	return 0;
}

D. 有限制的構造

一個\(dp\)但我 \(dp\) 一直不太好

初始模型是 \(f_{i,j,k}\) 表示前 \(i\) 個,畫面質量是 \(j\) ,不可玩度是 \(k\) 時的個數,但陣列開不下,遂捨棄

觀察到 \(n\) 最大80,所以我們可以把答案放陣列裡,則\(f_{i,j,k}\) 表示前 \(i\) 個,選 \(j\) 個,畫面質量是 \(k\) 時,的不可玩度最小值

我們強制讓 \(k\) 在範圍內,最後再隨便選一個即可,但 \(256MiB\),還是開不下,滾動陣列最佳化一下就好了

點選檢視程式碼
#include<bits/stdc++.h>
const int maxn=1e4+10;
using namespace std;
int n,A,B,ans,a[100],b[100],f[2][82][maxn];

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>A>>B;
	for(int i=1;i<=n;i++)
		cin>>a[i]>>b[i];
	memset(f,0x7f,sizeof f);
	f[1][0][0]=f[0][0][0]=0;	
	for(int i=1;i<=n;i++)
	{
		int temp=i&1;
		for(int j=1;j<=i;j++)
		{
			for(int k=0;k<=A;k++)
			{
				if(k>=a[i])f[temp][j][k]=f[temp^1][j-1][k-a[i]]+b[i];
				f[temp][j][k]=min(f[temp][j][k],f[temp^1][j][k]);
			}
		}
	}
	for(int i=n;i>=0;i--)
	{
		for(int j=0;j<=A;j++)
		{
			if(f[1][i][j]<=B||f[0][i][j]<=B)
			{
				cout<<min(i+1,n);
				return 0;	
			}
		}
	}

	
	return 0;
}

相關文章