231014校内赛

T1 进制转换

pipXonS.jpg

题解

经典题意越短越难系列

对于每一个询问的答案有个明显的限制,小于 \(\log_2n\)

所以在暴力计算答案时有一个小优化,大于了上界就直接退出循环

进一步思考如何优化暴力

对于 \(< \lceil \sqrt n \ \rceil\) 的数,可以直接暴力求解

对于 \(>\lceil \sqrt n \ \rceil\) 的数,因为转换进制后只有两位,所以可以枚举两位中的最高位,算出相应进制,如果进制大于了 \(k\) 那就当作 \(k\) 再处理

#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
	freopen("base.in","r",stdin);
	freopen("base.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;cin>>T;
	while(T--){
		int n,k,ans = 33,lim;cin>>n>>k;
		lim = ceil(sqrt(n));
		for(int i = 2;i<=min(lim,k);i++){
			int tmp = n,res = 0;
			while(tmp){
				res+=tmp%i;
				tmp/=i;
				if(res>=ans) break;
			}
			ans = min(ans,res);
		}
		int tmp = n/(lim+1);
		for(int i = min(tmp,ans);i>=1;i--){
			int base = n/i;
			if(base>k){
				int x = (n/(i+1))+1;
				if(x>k) break;
				base = k;
			}
			ans = min(ans,i+(n%base));
		}
		cout<<ans<<"\n";
	}
	return 0;
}

T2 序列计数

piPb7gP.jpg

题解

对于这道题,很明显是可以暴力 \(dp\)\(\mathcal O(n^3)\) 的部分分的题解写的,我不会这部分分

然后题解说的可以用前缀和优化掉一个 \(n\)

然后就是考虑容斥 \(dp\) ,有以下两种思路只会第一种

  1. 对于一段 \(1\) 一段 \(0\) 的序列转为一段 \(1\) 加一个 \(0\) 的结构,可以看成序列 \(a_1,a_2,a_3,\ldots ,a_k\) ,其中 \(a_i\) 表示第 \(i\)\(1\) 的长度
  2. 对于每一段 \(1\) 的段尾进行容斥

对于每一个 \(i\) 我们认为有 $0 \sim \frac n i $ 个不满足条件

对于每一个 \(f_i\) 我们表示连续段长度 \(\le i\) 的方案数,对于最后输出恰好为 \(i\) 也就是 \(f_i-f_{i-1}\)

对于所有情况来说,每一位都是随便选,所以就是 \(2^n\)

每一个串的长度为 \(i+1\)\(i\)\(1\) 和一个 \(0\)

然后用容斥原理来出去我们算重复的和不满足限制条件的,算 \(f\) 两个循环都是在做这件事

对于式子我也不是很会推,以后再补

#include<bits/stdc++.h>
#define int long long
#define N 1000010
#define mod ((int)1e9+7)
using namespace std;
int n,fac[N],inv[N],f[N],pw[N];
int ksm(int x,int y){
	int res = 1;
	while(y){
		if(y&1) res = res*x%mod;
		x = x*x%mod;y>>=1;
	}
	return res;
}
int C(int x,int y){
	return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
signed main(){
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	fac[0] = pw[0] = 1;
	for(int i = 1;i<=n;i++){
		fac[i] = fac[i-1]*i%mod;
		pw[i] = 2*pw[i-1]%mod;
	}
	inv[n] = ksm(fac[n],mod-2);
	for(int i = n-1;i>=0;i--) inv[i] = inv[i+1]*(i+1)%mod;
	for(int i = 1;i<=n+1;i++){
		f[i] = pw[n];
		for(int j = 1;j*(i+1)<=n;j++){
			if(j&1) f[i] = (f[i]+mod-C(n-i*j,j)*pw[n-(i+1)*j]%mod)%mod;
			else f[i] = (f[i]+C(n-i*j,j)*pw[n-(i+1)*j]%mod)%mod; 
		}
		for(int j = 0;(i+1)*j+i<=n;j++){
			if(j&1) f[i] = (f[i]+C(n-i*(j+1),j)*pw[n-(i+1)*j-i]%mod)%mod;
			else f[i] = (f[i]+mod-C(n-i*(j+1),j)*pw[n-(i+1)*j-i]%mod)%mod;
		}
	}
	for(int i = 1;i<=n+1;i++)
		cout<<(f[i]-f[i-1]+mod)%mod<<" ";
	return 0;
}

T3 01串

piPxSC4.jpg

题解

不考虑动的位置,考虑不动的位置

相当于不动的位置顺序不变,动的位置按照任意顺序放在序列末尾

回文串和变化很大的顺序可以让人联想到区间 \(dp\)

我们只需要不动的那些位置不违背回文串的条件,并且剩下的位置可以满足可以凑成回文串即可

\(n\) 是偶数可以令 \(f_{l,r,k}\) 表示区间 \([l,r]\),选出了 \(k\)\(1\),最多能选几对 \(0\) 使得选出的东西是回文串

转移和普通区间 \(dp\) 是类似的,需要注意奇数的情况类似,不过处理的细节不完全一样

时间复杂度 \(\mathcal O(n^3)\)

#include<bits/stdc++.h>
#define N 1000010
#define mod 998244353
using namespace std;
int n,m,ans,a[N],f[310][310][310],num[2],sum[310][2],s[N];
char c[N];
int main(){
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>c+1;
	for(int i = 1;i<=n;i++){
		s[i] = c[i]%2;
		num[s[i]]++;
	}
	if(n&1){
		for(int i = 1;i<=n;i++)
			if(num[s[i]]&1) f[i][i][0] = 1;
	}else for(int i = 1;i<n;i++) f[i+1][i][0] = 0;
	for(int i = 1;i<=n;i++){
		sum[i][0] = sum[i-1][0];
		sum[i][1] = sum[i-1][1];
		sum[i][s[i]]++;
	}
	if(n%2==0&&num[0]%2==1){
		cout<<"-1";
		return 0;
	}
	if(num[0]&1) num[0]--;
	if(num[1]&1) num[1]--;
	for(int l = n;l;l--)
		for(int r = l+1;r<=n;r++)
			for(int k = 0;k<=r-l+1;k++){
				f[l][r][k] = max(f[l][r-1][k],f[l+1][r][k]);
				if(s[l]==s[r]&&k>=s[l]&&(n%2==0||f[l+1][r-1][k-s[l]]%2==1))
					f[l][r][k] = max(f[l][r][k],f[l+1][r-1][k-s[l]]+2);
			}
	ans = n>>1;
	for(int l = 1;l<=n;l++)
		for(int r = l;r<=n;r++)
			for(int k = 0;k<=n;k++)
				if(f[l][r][k]){
					int tmp1 = num[1]-k*2,tmp2 = num[0]-(f[l][r][k]-k*2-f[l][r][k]%2);
					if(sum[l-1][1]>=(tmp1>>1)&&sum[l-1][0]>=(tmp2>>1))
						ans = max(ans,f[l][r][k]+min(tmp1>>1,sum[l-1][1])+min(tmp2>>1,sum[l-1][0]));
				}
	cout<<n-ans;
	return 0;
}

T4

照例,没碰

posted @ 2023-10-18 21:15  cztq  阅读(2)  评论(0编辑  收藏  举报