2021CCPC哈尔滨VP+补题记录(更新至5题BDEIJ)

发布时间 2023-11-09 09:43:41作者: Hssliu

碎碎念

时限3h打了五题铜,感觉还没有把可做题全部写完,待补

J. Local Minimum

记录行最小值和列最小值,遍历一遍矩阵判断当前值是否同时是行最小值与列最小值,记录答案即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define inf 0x3f3f3f3f
const int N=1000+100;
int t,n,m,q,a[N][N],minr[N],minc[N];
vector<int> g[N];
string s;
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) cin>>a[i][j];
	}
	for(int i=1;i<=n;i++)
	{
		int mii=1e9;
		for(int j=1;j<=m;j++) mii=min(mii,a[i][j]);
		minr[i]=mii;
	}
	for(int j=1;j<=m;j++)
	{
		int mii=1e9;
		for(int i=1;i<=n;i++) mii=min(mii,a[i][j]);
		minc[j]=mii;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(min(minr[i],minc[j])==a[i][j]) ans++;
		}
	}
	cout<<ans;
}

main()
{
	IOS;
	solve();
}

B. Magical Subsequence

小dp,记录 \(dp[i][j]\) 表示当前匹配到 \(i\) 位,选择和为 \(j\) 的最大长度。

\[dp[i][j]=max(dp[i-1][j],dp[LastOccrrenceIndexof(j-a[i])-1][j]+2) \]

其中 $ LastOccrrenceIndexof(j-a[i])$ 表示最近的值为 \(j-a[i]\) 的元素出现的位置,可以 \(O(n)\) 地预处理出来。

注意一丢丢不要匹配到负数下标的小细节

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define inf 0x3f3f3f3f
const int N=1e5+100;
int t,n,m,q,a[N],f[N][201],g[N][201];

void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=100;j++)
		{
			g[i][j]=g[i-1][j];
		}
		g[i][a[i]]=i;
	}
	for(int i=1;i<=n;i++)
	{
		for(int x=2;x<=200;x++)
		{
			
			f[i][x]=max(f[i][x],f[i-1][x]);
			int now=x-a[i];
			//if(x==2) cout<<f[i][x]<<' '<<g[i-1][now]<<' '<<f[g[i-1]][now]<<'\n';
			if(now>=1&&now<=100)
			{
				if(g[i-1][now]>0) f[i][x]=max(f[i][x],f[g[i-1][now]-1][x]+2);
			}
		}
	 }
	int ans=0;
	for(int i=2;i<=200;i++) ans=max(ans,f[n][i]);
	cout<<ans;  
}

main()
{
	solve();
}

E. Power and Modulo

找到第一个 \(a[i]!=a[i-1]\time 2\) 的位置,即可知道 \(mod=2\time a[i-1] - a[i]\) ,遍历数组判断是否满足 \(a[i]=2^{i-1}%mod\) 即可。 需要考虑 \(a[1]!=1,mod<=0\) 这两种特殊情况。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define inf 0x3f3f3f3f
const int N=2e5+100;
int t,n,m,q,a[N];
vector<int> g[N];
string s;
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	int mod=-1;
	if(a[1]!=1)
	{
		for(int i=1;i<=n;i++)
		{
			if(a[i]!=0)
			{
				cout<<"-1\n";
				return;
			}
		}
		cout<<"1\n";
		return;
	}
	for(int i=2;i<=n;i++)
	{
		if(a[i]!=a[i-1]*2)
		{
			if(a[i]>a[i-1]*2)
			{
				cout<<"-1\n";return;
			}
			mod=2*a[i-1]-a[i];
			break;
		}
	}
	if(mod==-1) cout<<-1<<'\n';
	else
	{
		int b=1;
		for(int i=1;i<=n;i++)
		{
			if(a[i]!=b)
			{
				cout<<"-1\n";
				return;
			}
			b=b*2%mod;
		}
		cout<<mod<<'\n';
	}
}

main()
{
	cin>>t;
	while(t--) solve();
}

I. Power and Zero

按位拆分这个数组二进制第0位第31位每一位有多少个1,答案等同于删第0位的次数,而因为每次只能删去0i的一个前缀,需要满足序列单调不增,可以通过高位-1=低位+2来变换,大概想法是二分答案判断最多需要多少次,乱糊了一下发现就过了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define inf 0x3f3f3f3f
const int N=2e5+100;
int t,n,m,q,a[N],b[40],c[40];


bool check(int mid)
{
	memcpy(c,b,sizeof c);
	int nowmin=mid;
	for(int i=1;i<=32;i++)
	{
		//cout<<c[i];
		if(c[i]>nowmin) return false;
		int time=(nowmin-c[i])/2;
		c[i+1]-=time,c[i]+=time*2;
		nowmin=min(nowmin,c[i]);	
	}
	
	return true;
}

void solve()
{
	memset(b,0,sizeof b);
	memset(c,0,sizeof c);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=32;j++)
		{
			if((a[i]>>(j-1))&1) b[j]++;
		}
	}
	int l=0,r=1e9,mid;
	while(l<r)
	{
		mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
//	for(int i=1;i<=32;i++)
//	{
//		c[i]=b[i]-b[i-1];
//	}
//	for(int i=32;i>=2;i--)
//	{
//		if(c[i]<=0) continue;
//		int time=(c[i]+2)/3;
//		c[i]-=time*3,c[i-1]+=time*2;
//	}
	cout<<l<<'\n';
}

main()
{
	cin>>t;
	while(t--) solve();
}

D. Math master

2<<19枚举删除分子的哪些位,删完后确定新的分母,判断能否删除得到,有一些细节比如前导0需要注意。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define inf 0x3f3f3f3f
const int N=2e5+100;
int T,n,m,q;
int lens,lent;
vector<int> g[N];
string s,t;
int ansn,ansm; 

int stringtoint(string s)
{
	int ans=0;
	for(int i=0;i<(int)s.size();i++) ans=ans*10+s[i]-'0';
	return ans;
}

string inttostring(int x)
{
	int y=x;
	string ss;
	while(y) ss+='0'+y%10,y/=10;
	reverse(ss.begin(),ss.end());
	return ss;
}

void check(int num)
{
	int a[10]={0};
	string ss,tt;
	
	for(int i=0;i<lens;i++)
	{
		if((num>>i)&1)
		{
//			if(ss.size()==0&&s[i]=='0') return;
			ss+=s[i];
		} 
		else a[s[i]-'0']++;
	}

	int ssi=stringtoint(ss);
	if(ssi==0) return;
	int d=((__int128)ssi*(__int128)m)%(__int128)n;
	if(d!=0) return;
	int ssj=((__int128)ssi*(__int128)m)/(__int128)n;
	tt=inttostring(ssj);

	int p=tt.size()-1;
	int cnt=0;
	for(int i=(int)t.size()-1;i>=0;i--)
	{
		if(p>=0&&t[i]==tt[p]) p--;
		else {
			if(!(p==-1&&t[i]=='0')) a[t[i]-'0']--;
			else cnt++;
		}
	
	}

	bool flag=1;
	for(int i=0;i<10;i++) if(a[i]!=0)
	{
		if(i==0&&a[0]>0&&cnt>=a[0]) continue;
		flag=0;
	}
	if(p==-1&&flag)
	{
		if(ssi<ansn)
		{
			ansn=ssi,ansm=ssj;
		}
		return;
	}
}


void solve()
{
	cin>>n>>m;
	s=inttostring(n),t=inttostring(m);
	lens=s.size(),lent=t.size();
	ansn=n,ansm=m;
	for(int i=1;i<=(1<<lens)-1;i++)
	{
		check(i);
	}
	cout<<ansn<<' '<<ansm<<'\n';
}

main()
{
	cin>>T;
	while(T--) solve();
}