返回顶部

CSP17

请注意:题目背景与题目可能没有关系
image
第一题,性质题,找到序列的最大值与最小值,我们发现如果只有正数的话和只有负数的话都很好处理,正数正序处理类似前缀加,负数后缀加,那如果正负都有,该怎么办呢?其实我们可以吧序列全变为正的或负的吧,但是需要比较一下最大值最小值,如果都变成正的话,对被卡掉,例如1 1 1 1 1 1 1 1 -1e9就死了

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define pii pair<int,int>
using namespace std;
const int N = 1e5+5;
ll n,a[N],b[N];int cnt;
vector <pii> put;
void zh(int l,int r)
{
	for(int i=l;i<r;i++)
	{
		if(a[i]<=a[i+1])continue;
		a[i+1]+=a[i];
		put.pb({i,i+1});
		cnt++;
	}
}
void fu(int l,int r)
{
	for(int i=r;i>l;i--)
	{
		if(a[i]>=a[i-1])continue;
		a[i-1]+=a[i];
		put.pb({i,i-1});
		cnt++;			
	}
}
int main()
{
	speed();
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];b[i]=a[i];
	}
	sort(b+1,b+1+n);
	if(b[1]>=0)
	{
		zh(1,n);
		cout<<cnt<<endl;
		for(auto [l,r]:put)
		{
			cout<<l<<" "<<r<<endl;
		}
	}else
	{
		if(b[n]<=0)
		{
			fu(1,n);
			cout<<cnt<<endl;
			for(auto [l,r]:put)
			{
				cout<<l<<" "<<r<<endl;
			}
		}
		else
		{
			ll mx=b[n],pos=max_element(a+1,a+1+n)-a;
			ll mi=b[1],pp=min_element(a+1,a+1+n)-a;
			if(mx>-mi)
			{
				for(int i=n;i;i--)
				{
					int st=i;
					while(a[st]<=0&&st>0)
					{
						a[st]+=mx;
						put.pb({pos,st});
						if(mx<a[st])
						{
							mx=a[st];
							pos=st;
						}
						cnt++;
						st--;
					}
				}
				// for(int i=1;i<=n;i++)cout<<a[i]<<" ";
				zh(1,n);
				// for(int i=1;i<=n;i++)cout<<a[i]<<" "
				cout<<cnt<<endl;
				for(auto [l,r]:put)
				{
					cout<<l<<" "<<r<<endl;
				}				
			}else
			{
				for(int i=n;i;i--)
				{
					int st=i;
					while(a[st]>=0&&st>0)
					{
						a[st]+=mi;
						put.pb({pp,st});
						if(mi>a[st])
						{
							mi=a[st];
							pp=st;
						}
						cnt++;
						st--;
					}
				}
				// for(int i=1;i<=n;i++)cout<<a[i]<<" ";
				fu(1,n);
				// for(int i=1;i<=n;i++)cout<<a[i]<<" "
				cout<<cnt<<endl;
				for(auto [l,r]:put)
				{
					cout<<l<<" "<<r<<endl;
				}			
			}

		}
	}
	// for(int i=1;i<n;i++)
	// {
	// 	if(a[i]>a[i+1])
	// 	{
	// 		cout<<i<<" "<<a[i]<<" "<<a[i+1]<<endl;
	// 		cout<<"Wa"<<endl;
	// 		return 0;
	// 	}
	// }
	return 0;
}

image
这题,如果直接用暴力矩阵乘法的话是\(O(n^3)\),显然过不了,但我们可以发现一个性质,就是我们可以随机一个\(n\times 1\)矩阵,值得注意的是矩阵不满足交换律,但是\(randP \times A\times B \equiv randP\times C\)矩阵由\(n^2\)转换为\(n\)
这样我们就转换为\(O(n^2)\)的复杂度了

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const ll mod=998244353;
ll n;
mt19937 seed(random_device{}());
int rand(int l,int r)
{
	uniform_int_distribution<int>range(l,r);
	return range(seed);
}
struct Matrix
{
	vector <vector<ll>> a;
	int n,m;
	Matrix(int _n,int _m):n(_n),m(_m)
	{
		a.resize(n+1,vector<ll>(m+1));
	}
	void resize(int n,int m)
	{
		a.resize(n+1,vector<ll>(m+1));
	}
	Matrix operator * (const Matrix& A)const
	{
		Matrix ans(n,1);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=A.m;j++)
				for(int k=1;k<=m;k++)
					ans.a[i][j]=(ll)(ans.a[i][j]+(ll)a[i][k]*A.a[k][j]*1ll%mod)%mod;
		return ans;
	}
	void T()
	{
		cout<<"******"<<endl;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
				cout<<a[i][j]<<" ";
			cout<<endl;
		}
			
	}
};
int main()
{
	speed();
	// freopen("sequence2.in","r",stdin);
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
	int T;
	cin>>T;
	while(T--)
	{
		cin>>n;
		Matrix A(n,n),B(n,n),C(n,n),b(n,1);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)cin>>A.a[i][j];
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)cin>>B.a[i][j];
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)cin>>C.a[i][j];
		for(int i=1;i<=n;i++)
			b.a[i][1]=rand(1,16);
		// b.T();
		C=C*b;
		// C.T();
		b=B*b;//这里注意啊,为什么这么写A*(B*b)=C*b
		// b.T();
		b=A*b;
		// b.T();
		bool f=1;
		for(int i=1;i<=n;i++)
		{
			if(!f)break;
			for(int j=1;j<=1;j++)
			{
				if(b.a[i][j]!=C.a[i][j])
				{
					f=0;break;
				}
			}
		}
		if(f)cout<<"Yes"<<endl;
		else cout<<"No"<<endl;

	}
	return 0;
}

image

这题暴力分就是二维背包,考场上这都能写挂,挂了35分

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N = 1e4+5;
short n,A,B;short dp[N][N];
struct ac
{
	short a,b;
}q[N];
int ans;
bool vis[N];
void dfs(int a,int b,int cnt)
{
	if(a>A||b>B)
	{
		ans=max(ans,cnt);
		return;
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i])continue;
		vis[i]=1;
		dfs(a+q[i].a,b+q[i].b,cnt+1);
		vis[i]=0;
	}	
}
int main()
{
	speed();
	// freopen("construct2.in","r",stdin);
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>A>>B;
	short mx=0;
	for(int i=1;i<=n;i++)
	{
		cin>>q[i].a>>q[i].b;
		mx=max(q[i].a,mx);
		mx=max(q[i].b,mx);
	}
	mx=max(mx,A);mx=max(mx,B);
	// dfs(0,0,0);
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=mx;j>=q[i].a;j--)
		{
			for(int k=mx;k>=q[i].b;k--)
			{
				// if(j>=A&&j-q[i].a>=A)continue;
				// if(k>=B&&k-q[i].b>=B)continue;
				dp[j][k]=max<short>(dp[j][k],dp[j-q[i].a][k-q[i].b]+1);
				// if(j>=A&&j-q[i].a>=A)continue;
				// if(k>=B&&k-q[i].b>=B)continue;
				ans=max<short>(ans,dp[j][k]);
				// cout<<j<<" "<<k<<" "<<dp[j][k]<<endl;
			}
		}
	}
	// for(int i=0;i<=mx;i++)ans=max(ans,dp[A][i]);
	// for(int i=0;i<=mx;i++)ans=max(ans,dp[i][B]);
	cout<<dp[A][B]+(dp[A][B]!=n)<<endl;
	return 0;
}

正解
考虑到\(O(nV^2)\)\(V\)太大了,我们可以换一种枚举方式,换成\(f_{i,j,k}\)枚举前\(i\)人中选了\(j\)个人,\(A\)值为多少,复杂度为\(O(n^2V)\)这样就可以过了

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
using namespace std;
const int N = 1e4+5;
int n,A,B,dp[2][85][N];
struct ac
{
	int a,b;
}q[N];
bool cmp(ac a,ac b)
{
	return a.b<b.b;
}
int ans;
bool vis[N];

int main()
{
	speed();
	// freopen("construct2.in","r",stdin);
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>A>>B;
	int mx=0;
	for(int i=1;i<=n;i++)
	{
		cin>>q[i].a>>q[i].b;
		mx=max(q[i].a,mx);
		mx=max(q[i].b,mx);
	}
	mx=max(mx,A);mx=max(mx,B);
	memset(dp,0x3f,sizeof dp);
	dp[0][0][0]=0;;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=i;j++)
		{
			for(int v=A;v>=0;v--)
			{

				dp[i&1][j][v]=dp[(i-1)&1][j][v];
				if(j>=1&&v>=q[i].a)dp[i&1][j][v]=min(dp[i&1][j][v],dp[(i-1)&1][j-1][v-q[i].a]+q[i].b);
				// cout<<dp[i][j][v]<<endl;
				
			}
		}
	}
	for(int j=1;j<=n;j++)
		for(int v=A;v>=0;v--)
			if(dp[n&1][j][v]<=B)ans=max(ans,j);
	cout<<min(ans+1,n)<<endl;
	return 0;
}

此题还可以用模拟退火

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define y second
#define x first
#define int long long
using namespace std;
const int N = 2e5+5;
const double dw=0.998;
mt19937 rnd(std::chrono::steady_clock::now().time_since_epoch().count());
int n,A,B;
ll rd()
{
	uniform_int_distribution<int>range(1,INT_MAX);
	return range(rnd);
}

pii p[N];
int ans;
int calc()
{
	int s1=0,s2=0;
	for(int i=1;i<=n;i++)
	{
		s1+=p[i].x,s2+=p[i].y;
		if(s1>A||s2>B)
		{
			ans=max(ans,i);return i;
		}
	}

	ans=max(ans,n);return n;
}
void SA()
{
	sort(p+1,p+n+1);
	// random_shuffle(p+1,p+1+n);
	for(double t=1e5;t>=1e-7;t=t*dw)
	{
		int x=calc();int u=rd()%n+1;
		int v=rd()%n+1;swap(p[u],p[v]);
		int y=calc();if(y>x)continue;
		if((double)exp((double)(y-x)/t)>(double)rd()/RAND_MAX)continue;
		swap(p[u],p[v]);
	}
}
signed main()
{
	speed();
	// srand(time(0));
	// freopen("construct2.in","r",stdin);
	// freopen("in.in","r",stdin);
	// freopen("out.out","w",stdout);
	cin>>n>>A>>B;
	for(int i=1;i<=n;i++)
	{
		cin>>p[i].x>>p[i].y;
	}
	random_shuffle(p+1,p+1+n);
	for(int i=1;i<=200;i++)SA();
	cout<<ans<<endl;
	return 0;
}
posted @ 2024-08-11 16:31  wlesq  阅读(6)  评论(0编辑  收藏  举报