2025-10-30 ZYZOJ Star(斯达)模拟赛 hetao1733837的record

比赛背景: 很抱歉打扰大家,本人于2025年10月30日查出周期性蛋白脂肪缺乏症,学名lnsanus lovis,是一种广泛存在的慢性病,易感人群多为年轻群体,目前暂无有效的治愈方法,只能使用美国公司Kentucky Fired chicken开发的制剂Firend animal protein,经由食道对胃于小肠中受体进行靶向治疗缓解症状,今天该公司降低药物售价的日子,资助50帮我治疗该慢性病。

T1.palindrome

提交链接:题目详情 - palindrome - ZYZOJ

严肃认为数据过于水了。

题面

你有n种字母,其中第n种字母出现次数为a[i]。你想用这些字母拼成若干个串,要求第i种字母恰好
被用了a[i]次,并且要求每个串都是回文串,使得其中最短的串长度最大。
比如四种字符为'a', 'b', 'c', 'd',出现次数分别为{2,3,2,2},那么可能的其中几种方案为
{"acdbbbdca"}, {"abbba", "cddc"}, {"aca", "bbb", "dcd"}, 或{"acdbdca", "bb"}。第一种方案中,最短
的串长度为9,是最优的。

样例

输入:
cpp 复制代码
4
4
1 1 2 4
3
2 2 2
5 
1 1 1 1 1
5
1 1 2 2 3
输出:
cpp 复制代码
3
6
1
3

分析

这不是烫题吗?我们发现,偶数是一定可行的,然而奇数必须放在中间处理。那么把偶数拆分成长度为2的pair,每个奇数均摊,就可保证最短串最长了。而对于全是偶数,自然是直接相加即可。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 50005;
int T, n, a[N];
int main(){
	freopen("palindrome.in", "r", stdin);
	freopen("palindrome.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while (T--){
		cin >> n;
		int cnt_pair = 0;
		int cnt_1 = 0;
		long long sum = 0;
		for (int i = 1; i <= n; i++){
			cin >> a[i];
			cnt_pair += (a[i] / 2);
			if (a[i] % 2 == 1){
				cnt_1++;
			}
			sum += a[i];
		}
		if (cnt_1 <= 1){
			cout << sum << '\n';
			continue;
		}
		cout << 1 + cnt_pair / cnt_1 * 2 << '\n';
	}
}

T2.expression

提交窗口:题目详情 - expression - ZYZOJ

题面

你有n个数字a[1],a[2],...,a[n]和n−1个运算符op[1],op[2],...,op[n-1]排成一行,形如a[1] op1 a[2] op2 ... op[n-1] a[n]。其中运算符是+-*中的一个。
每次你会在剩余的数字里面,选出两个相邻的数字,根据它们之间的运算符计算出结果,然后把这两个数和这个运算符替换成算出来的结果。这样进行? − 1 轮之后只剩一个数字。
你想知道对于所有操作的方法,得到的最后的结果的和。两个操作的方法相同,当且仅当每一次操作两种操作方法选的数字位置都一样。
输出答案对10e9 + 7取模的结果,如果余数是负数,把它加上1e9 + 7 后输出。

样例

输入1:
cpp 复制代码
5
1 4 6 8 3
+*-*
输出1:
cpp 复制代码
999999689
输入2:
cpp 复制代码
10
517974382 763433648 185159600 390253537 104798220 734850655 170422025 748232829 820177910 110047331
输出2:
cpp 复制代码
123105432

分析

显然是区间dp吧......好吧,错误原因是认为这题是神秘思维,将*和-当成分割,然后连subtask都没过/(ㄒoㄒ)/~~

那么,我们好好想一下为啥是区间dp。主要还是因为这题按刚才思路,具备了完整的分段性质(运算符好像本来就是),同时,答案也是左右两端合并而来的。并且,神秘的数据范围给出了,机房大佬击球手说这就是区间dp的上线。好,考虑状态即转移。

表示一段计算的期望结果

转移 即为

最后还需乘上

时间复杂度

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
#define mod 1000000007
using namespace std;
const int N = 1005;
int n, dp[N][N];
int f[N]; //阶乘
int c[N][N]; //组合数
char op[N];
signed main(){
	freopen("expression.in","r",stdin);
	freopen("expression.out","w",stdout); 
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	f[0] = 1;
	for (int i = 1; i <= n; i++){
		cin >> dp[i][i];
		f[i] = f[i - 1] * i % mod;
		c[i][0] = 1;
	} 
	for (int i = 1; i < n; i++) 
		cin >> op[i];
	c[0][0] = 1;
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= n; j++){
			c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
		}
	}
	for (int l = 2; l <= n; l++){ //len
		for (int i = 1; i + l - 1 <= n; i++){
			int j = i + l - 1;
			for (int k = i; k < j; k++){
				int x = c[j - 1 - i][k - i];
				if (op[k] == '+') 
					dp[i][j] = (dp[i][j] + (f[k - i] * dp[k + 1][j] % mod + f[j - k - 1] * dp[i][k] % mod) * x % mod) % mod;
				if (op[k] == '-') 
					dp[i][j] = (dp[i][j] + (f[j - k - 1] * dp[i][k] % mod - f[k - i] * dp[k + 1][j] % mod) * x % mod + mod) % mod;
				if (op[k] == '*') 
					dp[i][j] = (dp[i][j] + dp[i][k] * dp[k + 1][j] % mod * x % mod) % mod;
			}
		}
	}
	cout << dp[1][n];
	return 0;
}

T3.square

提交链接:题目详情 - square - ZYZOJ

题面

你有个集合{1,2,3,...,n},你想在里面选出一个子集,满足:
Ⅰ.子集非空,并且大小不超过k。
Ⅱ.这些数字的乘积,不包含任何平方因子,也就是不能被任意大于等于2的数字的平方整除。
求选的子集的方案数,答案对1e9 + 7 取模。

样例:

输入1:
cpp 复制代码
6 4
输出1:
cpp 复制代码
19
输入2:
cpp 复制代码
100 20
输出2:
cpp 复制代码
368723819

分析

传言是神秘的状压dp,然而作为蒟蒻的我并非会......

浅写一下吧......

然后我们发现当时,质数少得可怜,直接暴力。

但题目数据居然是,那么我们引入根号分治的思想,对于的暴力枚举,剩余的进行状压(即选或不选)。

状压dp记录2~19质因子使用情况,剩下每个分为一组。

用dp[i][j][S]表示前i组数字,选了j个,前面8个质因子使用情况为S的方案数,然后要求每个组只能选一个,这样的方案数,直接计算即可。

然后就没了!?

正解

cpp 复制代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 610, mod = 1e9 + 7;
int n, lim, isp[N], p[N], idx, a[N], m, cnt[N], mk[N], ans, dp[10][10][N], up, f[N], lst[10][10][N];
int c[N][N];
vector<int> v[N];
signed main(){
	freopen("square.in", "r", stdin);
	freopen("square.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> lim;
	f[0] = 1;
	for (int i = 1; i <= n; i++) 
		c[i][0] = 1;
	for (int i = 2; i <= n; i++){
		if (isp[i]) 
			continue;
		p[++idx] = i;
		for (int j = 2 * i; j <= n; j+=i) 
			isp[j] = 1;
	}
	c[0][0] = 1;
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= n; j++){
			c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
		}
	}
	for (int i = 1; i <= idx; i++) 
		if (p[i] * p[i] <= n) 
			up++;
	for (int i = 2; i <= n; i++){
		int x = i, f = 0, ff = 0;
		for (int j = 1; j <= up; j++){
			if (x % p[j]) 
				continue;
			f |= (1 << j - 1);
			x /= p[j];
			if (x % p[j]) 
				continue;
			ff = 1;
			break;
		}
		if (ff) 
			continue;
		a[++m] = i;
		cnt[m] = f;
		mk[m] = (x != 1);
		if (mk[m]) 
			v[x].push_back(m);
	} 
	dp[0][0][0] = 1;
	for (int i = 1; i <= m; i++){
		if ((!cnt[i]) || mk[i]) 
			continue;
		for (int j = 0; j <= up; j++){
			for (int k = up; k >= 1; k--){
				for (int l = 0; l < (1 << up); l++){
					if ((l | cnt[i]) != l) 
						continue;
					if (j >= mk[i] && k >= 1) 
						dp[j][k][l] = (dp[j][k][l] + dp[j - mk[i]][k - 1][l ^ cnt[i]]) % mod;
				}
			}
		}
	}
	for (int r = p[up] + 1; r <= n; r++){
		for (int j = 0; j <= up; j++) 
			for (int k = 0; k <= up; k++) 
				for (int l = 0; l < (1 << up); l++) 
					lst[j][k][l] = dp[j][k][l];
		for (int i : v[r]){
			if (!cnt[i]) 
				continue;;
			for (int j = 0; j <= up; j++){
				for (int k = up; k >= 1; k--){
					for (int l = 0; l < (1 << up); l++){
						if ((l | cnt[i]) != l) 
							continue;
						if (j >= mk[i] && k >= 1) 
							dp[j][k][l] = (dp[j][k][l] + lst[j - mk[i]][k - 1][l ^ cnt[i]]) % mod;
					}
				}
			}
		}
	}
	for (int i = 1; i <= lim; i++){
		for (int j = 0; j <= up; j++){
			for (int k = 0; k <= min(lim, up); k++){
				for (int l = 0; l < (1 << up); l++){
					ans = (ans + dp[j][k][l] * c[idx - up - j + 1][i - k] % mod) % mod;
				}
			}
		}
	}
	cout << ans;
	return 0;
}

T4.color

提交链接:题目详情 - color - ZYZOJ

题面

你有一个n*m的棋盘,开始有些格子被染上了红色或者蓝色,有些格子没有颜色。你想对所有未染色的格子染上红色或者蓝色,使得棋盘中每个长宽都为偶数的矩形里面红色蓝色出现个数相同。
求染色的方案数,答案对1e9+7取模。

样例

输入
cpp 复制代码
3 3
???
?R?
???
输出
cpp 复制代码
7

大家猜我会吗?

直接上代码!

分析

首先一个条件是每个2×2的子矩形,里面的红色和蓝色个数是一样多的。如果棋盘中有两个相邻的元素同色,那么有如下

????BB????

????RR????

????BB????

????RR????

...

同时,对于每一列也一定是RB交替的,这样也一定满足条件。如果没有相邻的同色,那么整个矩形是红蓝相间的,也满足条件。换句话来说,把所有(i,j)满足i+j是偶数的位置,颜色红蓝反转,那么一定是所有行都同色或者所有列都同色。于是可以计算所有行同色所有列同色方案,减去两个都同色的情况即可.

正解

cpp 复制代码
#include<bits/stdc++.h>
#define int long long
#define N 1005
#define mod 1000000007
using namespace std;
int T=1,n,m,res;
char a[N][N],b[N][N];
int check(){
	int sum=1;
	for(int i=1;i<=n;i++){
		bool f1=1,f2=1;
		for(int j=1;j<=m;j++){
			if(j&1)b[i][j]='R';
			else b[i][j]='B';
			if(a[i][j]!='?'&&a[i][j]!=b[i][j]){
				f1=0;
				break;
			}
		}
		for(int j=1;j<=m;j++){
			if(j&1)b[i][j]='B';
			else b[i][j]='R';
			if(a[i][j]!='?'&&a[i][j]!=b[i][j]){
				f2=0;
				break;
			}
		}
		if(!f1&&!f2)return 0;
		if(f1&&f2)(sum*=2)%=mod;
	}
	return sum;
}
void solve(int cs){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	res=check();
	bool flag=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]=='?')continue;
			char c;
			if(a[i][j]=='R'){
				if(i&1)c='R';
				else c='B';
			}
			else{
				if(i&1)c='B';
				else c='R';
			}
			if(a[1][j]!='?'&&c!=a[1][j]){
				flag=0;
				break;
			}
			a[1][j]=c;
		}
	}
	if(flag){
		int tot=1;
		for(int j=1;j<=m;j++){
			if(a[1][j]=='?')(tot*=2)%=mod;
		}
		bool f1=1,f2=1;
		for(int j=1;j<=m;j++){
			if(a[1][j]=='?')continue;
			if(j&1){
				if(a[1][j]!='R'){
					f1=0;
					break;
				}
			}
			else{
				if(a[1][j]!='B'){
					f1=0;
					break;
				}
			}
		}
		for(int j=1;j<=m;j++){
			if(a[1][j]=='?')continue;
			if(j&1){
				if(a[1][j]!='B'){
					f2=0;
					break;
				}
			}
			else{
				if(a[1][j]!='R'){
					f2=0;
					break;
				}
			}
		}
		if(f1)(tot+=mod-1)%=mod;
		if(f2)(tot+=mod-1)%=mod;
		(res+=tot)%=mod;
	}
	cout<<res<<'\n';
}
signed main(){
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//	cin>>T;
	for(int cs=1;cs<=T;cs++){
		solve(cs);
	}
	return 0;
}

he的机房巨佬aoao的!

相关推荐
无敌最俊朗@6 小时前
C++ 值类别与移动语义详解(精简版)
java·数据结构·算法
lingran__6 小时前
算法沉淀第十一天(序列异或)
c++·算法
一匹电信狗7 小时前
【C++】红黑树详解(2w字详解)
服务器·c++·算法·leetcode·小程序·stl·visual studio
散峰而望7 小时前
Dev-C++一些问题的处理
c语言·开发语言·数据库·c++·编辑器
进击的大海贼7 小时前
QT/C++ 消息定时管理器
开发语言·c++·qt
寂静山林7 小时前
UVa 11853 Paintball
算法
kyle~7 小时前
原子性与原子操作
运维·服务器·开发语言·c++
第七序章7 小时前
【C + +】C++11 (下) | 类新功能 + STL 变化 + 包装器全解析
c语言·数据结构·c++·人工智能·哈希算法·1024程序员节
AA陈超8 小时前
虚幻引擎5 GAS开发俯视角RPG游戏 P06-29 属性信息委托
c++·游戏·ue5·游戏引擎·虚幻