2023杭电多校第六场 - 1 6 10

比赛地址:传送门
赛时过了 3 题,今天罚时多,而且出题慢
1001 思维签到题
1006 数学题
1010 倍增问题

1001 Count

题意
让你构造一个长为 n 的数组满足每个数均 $\in [1, m] $,且对于 $i \le k $,有 $A_i = A_{n - k + i} $。问你所有满足条件的数组的个数取模 998244353

思路
条件 2 将整个数组的前一半和后一半联系了起来,即 k 就是数组前后缀相等的个数。那么我们只需要确定剩下的不确定的位置就行了。

  • 当 $n = k $ 时,条件 2 相当于没有,所以答案即为 $m ^ n $
  • 当 $n \ne k $ 时,我们只需要确定剩下 \(n - k\)个位置即可,所以答案为 $ m ^ {n - k} $

代码

const int maxm = 2e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;

ll qpow(ll a, ll x){
	a %= mod;
	ll res = 1;
	while(x){
		if(x & 1) res = res * a % mod;
		x >>= 1;
		a = a * a % mod;
	}
	return res;
}

void solve(){
	ll n, m, k;
	cin >> n >> m >> k;
	if(n == k) cout << qpow(m, n) << '\n';
	else cout << qpow(m, n - k) << '\n';
	return ;
}

1006 Perfect square number

题意
给你长为 n 的数组,每个数的大小均在 $[1, 300] $ 之间。你尽可以操作一次,可以选择数组中任意的一个数,将其变为 $[1, 300] $ 之间的一个数。问你最大的区间个数满足这些区间和均为完全平方数。

思路
我们如果考虑每一个数在 $[1, 300] $ 里面选择,遍历每一个区间取最大值,那么 $O(n^4) $ 必定是 TLE 的。接下来我们考虑优化:

  • 对于每一个数来说,其修改后仅对包含其的区间产生影响;
  • 改变一个数 y 仅能影响区间和的范围是 \([sum - y + 1, sum - y + 300]\),而这个区间内的完全平方数的个数是远远小于 300 个的;

基于以上两点,我们可以先预处理出所有的完全平方数,再对每一个数 y 进行考虑:对于不包含该数的区间,满足题意的存下个数;对于包含该数的区间,求其当 y = 1 时的区间和,再在求得的完全平方数的序列中找到第一个大于等于其的位置,统计 \(y = [1, 300]\) 范围内哪些 y 可以使得当前区间和变为完全平方数,利用一个数组统计。那么,我们就得到了不包含当前数的合法区间数和包含当前数的合法 y 值。
最后我们循环遍历所有数,遍历其所有可能,取不包含 + 包含最大值的最大值即为最终答案
最终跑了 811 MS 应当是还存在更快的方法,日后再说
代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long

using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 1e3 + 5, inf = 0x3f3f3f3f, mod = 998244353;
bool v[maxm * maxm];
vector<int> f;

void pre(){
	f.push_back(0);
	for(int i = 1; i <= 300; ++ i){
		v[i * i] = true;
		f.push_back(i * i);
	}
	return ;
}

void solve(){
	int n;
	cin >> n;
	vector<int> a(n + 1), sum(n + 1), c(n + 1);
	vector<vector<int>> cnt(n + 1, vector<int>(310, 0));
	for(int i = 1; i <= n; ++ i){
		cin >> a[i];
		sum[i] = sum[i - 1] + a[i];
	}
	int len = f.size();
	for(int k = 1; k <= n; ++ k){
		for(int i = 1; i <= n; ++ i){
			for(int j = i; j <= n; ++ j){
				if(j < k || i > k){
					if(v[sum[j] - sum[i - 1]]){
						++ c[k];
					}
					continue;
				}
				int t = sum[j] - sum[i - 1] + 1 - a[k];
				auto it = lower_bound(f.begin(), f.end(), t) - f.begin();
				for(int l = it; l < len; ++ l){
					if(f[l] - t + 1> 300) break;
					++ cnt[k][f[l] - t + 1];
				}
			}
		}
	}
	int ans = 0;
	for(int i = 1; i <= n; ++ i){
		int temp = 0;
		for(int j = 1; j <= 300; ++ j){
			temp = max(temp, cnt[i][j]);
		}
		ans = max(ans, temp + c[i]);
	}
	cout << ans << '\n';
	return ;
}

signed main(){
	pre();
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}


1010 Calculate

题意
详见题目
有一个 n 个节点的图,每个顶点一定有唯一一条出边。如果说 Ming 当前手上拥有的数字为 \(y\),当他走到节点 i 时,手上的数字变为 $y \times k_i + b_i $。
给你 q 次询问,每次 Ming 从节点 x 出发走 l 步,初始手上数字为 y ,问你最终数字取模 1e9 + 7

思路
利用倍增维护即可,详见代码

代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long

using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int maxm = 1e5 + 5, inf = 0x3f3f3f3f, mod = 1e9 + 7, N = 30;
int n, q, p[maxm], k[maxm], b[maxm];
ll fk[maxm][N + 1], fb[maxm][N + 1], f[maxm][N + 1];
bool vis[maxm];

void solve(){
	mem(vis, false);
	mem(fk, 0); mem(fb, 0); mem(f, 0);
	cin >> n >> q;
	for(int i = 1; i <= n; ++ i) cin >> k[i];
	for(int i = 1; i <= n; ++ i) cin >> b[i];
	for(int i = 1; i <= n; ++ i){
		cin >> p[i];
		f[i][0] = p[i];
		fk[i][0] = k[p[i]];
		fb[i][0] = b[p[i]];
	}
	for(int i = 1; i <= n; ++ i){
		f[i][0] = p[i];
		fk[i][0] = k[p[i]] % mod;
		fb[i][0] = b[p[i]] % mod;
	}
	for(int i = 0; i < N; ++ i){
		for(int j = 1; j <= n; ++ j){
			f[j][i + 1] = f[f[j][i]][i];
			fk[j][i + 1] = fk[j][i] * fk[f[j][i]][i] % mod;
			fb[j][i + 1] = (fb[j][i] * fk[f[j][i]][i] % mod + fb[f[j][i]][i]) % mod;
		}
	}
	while(q--){
		ll x, y, l, ans;
		cin >> x >> l >> y;
		ans = y;
		for(int i = N; i >= 0; -- i){
			if(l >= (1ll << i)){
				l -= 1ll << i;
				ans = (ans * fk[x][i] % mod + fb[x][i]) % mod;
				x = f[x][i];
			}
		}
		cout << ans << '\n';
	}
	return ;
}

signed main(){
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}

posted on 2023-08-03 18:18  Qiansui  阅读(29)  评论(0编辑  收藏  举报