2024.12.28~2025.12.28 杂题选做

ABC400E

首先,我们设 \(p,q\) 为两个质数,那么 \(a=p^{2m}q^{2n}\)\(a\)\(400\) 数的充分必要条件

考虑枚举出 \(p^{2m}\),先跑质数筛。随后两两配对,大于 \(10^{12}\) 或溢出就 break,把这些数放入 vector,查询时二分即可,这样做 500ms 可以过。

优化思路

赛时没有想出来。

通过初一数学可得,\(p^{2m}q^{2n}=(p^mq^n)^2\)

因此我们枚举 \(p^m\)\(q^n\),保证其不超过 \(\sqrt{10^{12}}=10^6\)。最后放入平方即可。

P8933

本文作者:\(\color{red}\text{DoubleQLzn}\color{green}✓\)

题目:洛谷 P8933 [JRSKJ R7] 技巧性的块速递推 - 题目传送门

难度:\(\color{green}\tt 普及+\)

\(\text{Knowledge}\)

  • \(5\)】深度优先搜索

\(\text{Solution}\)

观察题目,考虑特殊性质

思考四个数 \((a,b,c,d)\) 什么时候满足条件。

首先,当后面的条件满足时,前面一定满足。

因此考虑后面的条件,只有当 \(2\)\(2\) 白时满足。知道前 \(3\) 个就可以推出第 \(4\) 个。

所以,填的颜色具有周期性,\(2\) 个周期后方案确定,因此 \(n>5,m>5\) 的答案是 \(n=5,m=5\),预处理答案,这部分深度优先搜索即可。

\(\text{Code}\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
int ans[12][12],a[12][12],m,n;
int same(int a,int b,int c)
{
	if (a == b && b == c) return 1;
	else return 0;
}
int s2(int a,int b,int c,int d)
{
	unordered_map<int,int> f2;
	f2[a]++,f2[b]++,f2[c]++,f2[d]++;
	if (f2[1] == 3 || f2[0] == 3) return 1;
	else return 0;
}
bool check()
{
	for (int i = 1;i <= m;i++)
	{
		for (int j = 1;j <= n;j++)
		{
			
			if (i + 2 <= m && same(a[i][j],a[i + 1][j],a[i + 2][j])) return 0;
			if (j + 2 <= n && same(a[i][j],a[i][j + 1],a[i][j + 2])) return 0;
			if (i + 2 <= m && j + 2 <= n && same(a[i][j],a[i + 1][j + 1],a[i + 2][j + 2])) return 0;
			if (i + 2 <= m && j - 2 >= 1 && same(a[i][j],a[i + 1][j - 1],a[i + 2][j - 2])) return 0;
		}
	}
	for (int i = 1;i <= m;i++)
	{
		for (int j = 1;j <= n;j++)
		{
			
			if (i + 3 <= m && s2(a[i][j],a[i + 1][j],a[i + 2][j],a[i + 3][j])) return 0;
			if (j + 3 <= n && s2(a[i][j],a[i][j + 1],a[i][j + 2],a[i][j + 3])) return 0;
			if (i + 3 <= m && j + 3 <= n && s2(a[i][j],a[i + 1][j + 1],a[i + 2][j + 2],a[i + 3][j + 3])) return 0;
			if (i + 3 <= m && j - 3 >= 1 && s2(a[i][j],a[i + 1][j - 1],a[i + 2][j - 2],a[i + 3][j + 3])) return 0;
		}
	}
	return 1;
}
int s = 0;
void dfs(int x,int y)
{
	if (y > n) y= 1,x++;
	if (x > m)
	{
		if (check())
		{
			ans[m][n] = (ans[m][n] + 1) % 998244353;
		}
		return ;
	}
		a[x][y] = 1;
		dfs(x,y + 1);
		a[x][y] = 0;
		dfs(x,y + 1);
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	memset(a,-1,sizeof a);
	for (int i = 1;i <= 5;i++)
	{
		for (int j =1;j <= 5;j++)
		{
			memset(a,-1,sizeof a);
			m = i,n = j;
			dfs(1,1);
		
		}

	}
	int T,x,y;
	cin >> T;
	while (T--)
	{
		cin >> x >> y;
		cout << ans[min(x,5ll)][min(y,5ll)] << '\n';
	}
	return 0;
}

ABC391E

首先观察每个区间的答案,将其分为 \(3\) 个子区间 \(a,b,c\),定义一个区间的值为其的 \(A^{'}\)\(2\) 种情况:

  • \(a,b,c\) 的值相等:最小花费为 \(a,b,c\) 的花费中前两小的和;
  • \(a,b,c\) 的值不等:最小花费为原本值相等的两个子区间中花费的最小值。

由于每次都分成三个区间,具有递归特性,使用递归实现即可。

Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
int a[4000005];
int solve(int a,int b,int c)
{
	int f[4] = {0};
	f[a]++,f[b]++,f[c]++;
	if (f[0] > f[1]) return 0;
	else return 1;
}
int qsort1(int a,int b,int c)
{
	vector<int> d;
	d.push_back(a),d.push_back(b),d.push_back(c);
	sort(d.begin(),d.end());
	return d[0] + d[1];
}
int now=0;
pair<int,int> dfs(int l,int r)
{
	now++;
	//if (l > r) return make_pair(0,0);
	//cout<<l<<' '<<r<<endl;
	if (l == r) return make_pair(a[l],1);
	else 
	{
		// 1 3 2 2 3 3 
		int l1 = l,r1 = l1 + (r - l + 1) / 3 - 1;
		int l2 = r1 + 1,r2 = r1 + ((r - l + 1) / 3);
		int l3 = r2 + 1,r3 = r;
	//	cout<<l1<<' '<<l2<<' '<<l3<<' '<<r1<<' '<<r2<<' '<<r3<<' ';
		pair<int,int> a = dfs(l1,r1);
		pair<int,int> b = dfs(l2,r2);
		pair<int,int> c = dfs(l3,r3);
		int ans1 = solve(a.first,b.first,c.first);
		int ans2;
		if (a.first == b.first && b.first == c.first) ans2 = qsort1(a.second,b.second,c.second);
		else 
		{
			if (a.first == b.first) ans2 = min({a.second,b.second});
			if (a.first == c.first) ans2 = min({a.second,c.second});
			if (b.first == c.first) ans2 = min({b.second,c.second});
		}
		return make_pair(ans1,ans2);
	}
}
signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
	int n;
	cin >> n;
	int len = 1;
	for (int i = 1;i <= n;i++) len *= 3;
	for (int i = 1;i <= len;i++)
	{
		char c;
		cin >> c;
		a[i] = c - 48;
	}
	cout << dfs(1,len).second;
	return 0;
}

P11229

分类讨论简单题。

我们先求出每个数字需要的火柴数量。

| 数字 | 需要火柴数量 |
| :--------: | :-------: |
| $0$ | $6$ | 
| $1$ | $2$ |
| $2$ | $5$ | 
| $3$ | $5$ |
| $4$ | $4$ | 
| $5$ | $5$ |
| $6$ | $6$ | 
| $7$ | $3$ |
| $8$ | $7$ |
| $9$ | $6$ |

想要让数字最小,首先就要让 **位数** 最小,很明显,**要尽可能地多使用 $\bold{8}$**。

知道整体策略后,我们可以找一下规律,从数据范围不难看出,答案和 $7$ 与取模有关,继续找规律。

| 数字与取余值 | 结果 |
| :-------: | :---------: |
| $28 \bmod 7=0$ | $8888$ | 
| $29 \bmod 7=1$ | $10888$
| $30 \bmod 7=2$ | $18888$ |
| $31 \bmod 7=3$ | $20088$ |
| $32 \bmod 7=4$ | $20888$ | 
| $33 \bmod 7=5$ | $28888$ |
| $34 \bmod 7=6$ | $68888$ |

很容易发现,对于每个数字 $x$,结尾均有 $\lfloor{x\div 7}\rfloor-2$ 个 $8$,前面则各不相同,这也是结论。

同时,不要忘了小数据打表,要打表到 $14$。

综上,可以 AC 本题。

### 考场代码 ($0$ 分)

开的 `string a[100005]`。

MLE。

### AC 代码

```cpp
#include <bits/stdc++.h>
using namespace std;
string f[100005] = {"-1","-1","1","7","4","2","6","8","10","18","22","20","28","68","88","108","188","200","208","288","688","888","1088","1888","2008","2888","6888","8888","10888"};
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		if (n <= 14) cout << f[n] << endl;
		else
		{
			int k = n / 7 - 1;
			string b;
			for (int i = 1;i < k;i++) b.push_back('8');
			if (n % 7 == 0) cout << "88" << b;
			if (n % 7 == 1) cout << "108" << b;
			if (n % 7 == 2) cout << "188" << b;
			if (n % 7 == 3) cout << "200" << b;
			if (n % 7 == 4) cout << "208" << b;
			if (n % 7 == 5) cout << "288" << b;
			if (n % 7 == 6) cout << "688" << b;
			cout << '\n';
		}
	}
	return 0;
}

CF2044E

我们可以求出 $k$ 的所有非负整数次幂 $x_1,x_2,\cdots,x_{log_k{10^9}}$。然后枚举所有满足要求的数,对于任意 $x_i$,如果 $a$ 满足要求,应该满足下面四个不等式:

- $x_ia\geq l2$
- $x_ia\leq r2$
- $a\geq l_1$
- $a\leq r_2$

不妨移项,$a\geq l2\div a$,$a\leq r2\div a$,前者上取整,后者下取整,就是前两个不等式的解集。

最后求两个解集的交叉部分即可。

### Code

```cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
int t,k,l1,r1,l2,r2;
int jiaocha(int l1,int r1,int l2,int r2)
{
	int s = min(r1,r2) - max(l1,l2) + 1;
	return max(0ll,s);
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> t;
	while (t--)
	{
		cin >> k >> l1 >> r1 >> l2 >> r2;
		vector<int> g;
		int now = 1;
		while (now <= 1000000000)
		{
			g.push_back(now);
			now = now * k;
		}
		int ans = 0;
		for (auto a : g)
		{
			int down = ceil(l2 * 1.0 / a),up = r2 / a;
			ans = ans + jiaocha(down,up,l1,r1);
		}
		cout << ans << '\n';
	}
	return 0;
}
posted @ 2025-12-28 17:09  lzn_tops  阅读(0)  评论(0)    收藏  举报