2021/01/17训练总结

前言

放假&开始训练的第一天。寒假应该会每天都会训练了,记录一下一天收获和写一些题解,现在洛谷1160题,看寒假结束能有多少吧。今天主要是写写了两题数位dp然后把牛客小白赛31补完了。(我会记住上海站面对数位dp时的无力)

P4317 花神的数论题

题目链接:P4317 花神的数论题
题目大意:
在这里插入图片描述
数据范围: 1 ≤ N ≤ 1 0 15 1\le N\le10^{15} 1N1015
题解:我们考虑去计算 1 − N 1-N 1N s u m ( i ) = x sum(i)=x sum(i)=x的个数,然后累乘起来就行了。现在问题就是如何求出 s u m ( i ) = x sum(i)=x sum(i)=x i i i的个数。我们采取记忆化搜索(数位dp)的方法来进行。重要讲解一下 d f s dfs dfs函数,参数里面 c u r cur cur表示剩余位数, u p up up表示是否顶着上界, n o w now now表示现在已经遍历出来的1的个数, q u e que que表示要求的1的个数。
AC代码:

#include<bits/stdc++.h>

#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200000 + 10;
const int mod = 10000007;
#define int long long
ll fpow(int x, int y)
{
	int ans = 1;
	while (y)
	{
		if (y & 1)ans = 1ll * ans * x % mod;
		x = 1ll * x * x % mod; y >>= 1;
	}
	return ans;
}
int w[55];
int f[55][2][55][55];
int dfs(int cur, int up, int now, int que)
{
	if (!cur)
	{
		return now == que;
	}

	if (~f[cur][up][now][que])return f[cur][up][now][que];
	int tp = up ? w[cur] : 1;
	int ans = 0;
	for (int i = 0; i <= tp; i++)
	{
		ans = (ans + dfs(cur - 1, up && i == tp, now + (i == 1), que));
	}
	return f[cur][up][now][que] = ans;
}
signed main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	ll n;
	read(n);
	while (n)
		w[++w[0]] = n & 1, n >>= 1;
	ll ans = 1;
	memset(f, -1, sizeof(f));
	for (int i = 1; i <= w[0]; i++)
	{
		ans = ans * fpow(i, dfs(w[0], 1, 0, i)) % mod;
	}
	printf("%lld\n", ans);
	return 0;
}

P4127 [AHOI2009]同类分布

题目链接:P4127 [AHOI2009]同类分布
题目大意:
在这里插入图片描述
数据范围: 1 ≤ a ≤ b ≤ 1 0 18 1≤a≤b≤10^{18} 1ab1018
题解:很明显的数位dp,基本上数位dp都是要求 1 − n 1-n 1n中有多少个数满足xx要求,我们用 f i n d ( n ) find(n) find(n)函数来代替,这题答案就是 f i n d ( b ) − f i n d ( a − 1 ) find(b)-find(a-1) find(b)find(a1),我们考虑 f i n d ( n ) find(n) find(n)这个函数要怎么求,一般来说数位dp的搜索函数都要有这几个参数, c u r cur cur表示还剩多少位, l i m i t limit limit表示是否顶着上界,然后有几个参数用来判断是否满足条件和剪枝。这题里面 s u m sum sum表示搜索的数的数位和是多少, r e m rem rem表示搜索的数模 m o d mod mod后的值,其中 m o d mod mod表示我们要求的数位和。
AC代码:

#include<bits/stdc++.h>

#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 200 + 10;
#define int long long
ll f[20][163][163], w[N];
int mod;
ll dfs(int cur, int sum, int rem, int limit)
{
	if (!cur)
	{
		return (mod == sum) && (rem == 0);
	}
	if (!limit && ~f[cur][sum][rem])return f[cur][sum][rem];
	if (sum > mod || sum + 9 * cur < mod)return 0;
	int tp = limit ? w[cur] : 9;
	ll ans = 0;
	for (int i = 0; i <= tp && sum + i <= mod; i++)
	{
		ans += dfs(cur - 1, sum + i, (rem * 10 + i) % mod, limit && (i == tp));
	}
	return f[cur][sum][rem] = ans;
}
ll find(ll x)
{
	w[0] = 0;
	while (x)
		w[++w[0]] = x % 10, x /= 10;
	ll ans = 0;
	for (mod = 1; mod <= w[0] * 9; mod++)
	{
		memset(f, -1, sizeof(f));
		ans += dfs(w[0], 0, 0, 1);
	}
	return ans;
}
signed main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	ll a, b;
	read(a), read(b);
	printf("%lld\n", find(b) - find(a - 1));

	return 0;
}

小白赛31A

题目链接:A|B
题目大意:
在这里插入图片描述
数据范围: t < = 1 e 5 t<=1e5 t<=1e5, 1 ≤ a , x ≤ 1 0 9 1≤a,x≤10^9 1a,x109
题解:题目一看还以为数位dp,在看 t t t 1 e 5 1e5 1e5数量级,明显排除数位dp。我们来考虑,没有第一个限制的情况,假设a是 10101010 10101010 10101010,b只要对于a的二进制为1的位填上0即可,而a的二进制为0的位,b可以选择0|1,所以答案就是 2 a 二 进 制 数 中 0 的 个 数 2^{a二进制数中0的个数} 2a0。我们现在再加上限制,假设x是 10101010 10101010 10101010,对于我们假设当前遍历选择的b前缀都和x相同,例如我们现在遍历到了第4位,那么我们选择的b前缀都是 1010 1010 1010。我们考虑x每一个为1的位,我们新增答案,我们可以假设b在当前位置为0,那么我们后面的位就相当于没有x的限制了,因为无论我们怎么选择都不会超过x。所以新增 2 a 剩 余 二 进 制 数 中 0 的 个 数 2^{a剩余二进制数中0的个数} 2a0。这样我们遍历了 0 ∼ x − 1 0\sim {x-1} 0x1,再加上x并且去除0,就可以得到答案
AC代码:

#include<bits/stdc++.h>

#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
//#define int long long
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
ll t, a, x;

signed main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	read(t);
	while (t--)
	{

		read(a), read(x);
		ll ans = 0;
		for (int i = 31; i >= 0; i--)
		{
			if (((1ll << i) & x) == 0)continue;
			int c = 0;
			for (int j = i - 1; j >= 0; j--)
				if (((1ll << j) & a)==0)c++;
			ans += (1ll << c);
			if (((1ll << i) & a))break;
		}
		if ((a | x) == (a + x))ans++;
		printf("%lld\n", ans - 1);

	}

	return 0;
}

小白赛31E 解方程

题目链接:解方程
题目大意:
在这里插入图片描述
数据范围: 1 ≤ t ≤ 1 0 3 1≤t≤10^3 1t103, 1 ≤ a , b ≤ 1 0 6 1 \le a, b \le 10^6 1a,b106
题解:其实之前就遇见过类似的,不过还是没记住这种题目的套路,一般看见x*y这种式子就要想着如何去进行因式分解,这题就是两边加上 a ∗ b a*b ab得到 a ∗ x + b ∗ y + a ∗ b = x ∗ y + a ∗ b a*x+b*y+a*b=x*y+a*b ax+by+ab=xy+ab,移项得到 a ∗ b = x ∗ y − a ∗ x − b ∗ y + a ∗ b a*b=x*y-a*x-b*y+a*b ab=xyaxby+ab a ∗ b = ( x − a ) ∗ ( y − b ) a*b=(x-a)*(y-b) ab=(xa)(yb)答案就是求 a ∗ b a*b ab的因子数。暴力 ( O n ) (O\sqrt{n}) (On )求解肯定是不行的,拿唯一分解定理搞一下就行
AC代码:

#include<bits/stdc++.h>

#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
	T res = 0, f = 1; char c = getchar();
	while (!isdigit(c)) {
		if (c == '-')f = -1; c = getchar();
	}
	while (isdigit(c)) {
		res = (res << 3) + (res << 1) + c - '0'; c = getchar();
	}
	x = res * f;
}
const ll N = 2000000 + 10;
const int mod = 1e9 + 7;
int t, a, b;
int prime[N];
bool fprime[N];
void init(int n)
{
	for (int i = 2; i <= n; i++)
	{
		if (!fprime[i])prime[++prime[0]] = i;
		for (int j = 1; j <= prime[0] && i * prime[j] <= n; j++)
		{
			fprime[prime[j] * i] = 1;
			if (i % prime[j] == 0)break;
		}
	}
}
int solve(ll x)
{
	int ans = 1;
	for (int j = 1; j <= prime[0] && prime[j] * prime[j] <= x; j++)
	{
		int cnt = 0;
		while (x % prime[j] == 0)x /= prime[j], cnt++;
		ans *= cnt + 1;
	}
	if (x != 1)ans *= 2;
	return ans;
}
int main()
{
	//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
	freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
	init(1000000);
	read(t);
	while (t--)
	{
		read(a), read(b);
		
		printf("%d\n", solve(a*b));
	}

	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值