比赛链接:

https://ac.nowcoder.com/acm/contest/11186

A.小y的平面

思路:

因为只能向右或者向上走,所以能走的下一个点只能在右上
依据 x + y 的值对点进行一个排序(我没排序也过了,测试点好像有点水),然后循环判断就可以了。

代码:

#include <bits/stdc++.h>
using namespace std;
#define all(x) (x).begin(), (x).end()
#define fi first
#define LL long long
#define pb push_back
#define PII pair <int, int>
#define se second
const int N = 1e6 + 10, M = 2e5 + 10;
const int mod = 1e9 + 7;
LL T = 1, n;
string s;
struct node{
	int x, y;
}p[N];
bool cmp(node a, node b){
	return a.x + a.y < b.x + b.y;
}
void solve(){
	cin >> n;
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &p[i].x, &p[i].y);
	sort(p + 1, p + n + 1, cmp);
	for (int i = 2; i <= n; i++)
		if (p[i].x < p[i - 1].x || p[i].y < p[i - 1].y){
			cout << "NO\n";
			return;
		}
	cout << "YES\n";
}
int main(){
//	cin >> T;
	while(T--)
		solve();
	return 0;
}

B.小y的树

思路:

定义根节点为树的第 0 层,其子节点为第 1 层,那么这颗树总共有 \(n - 1\) 层,我们一层一层考虑。
根节点(即第 0 层)到所有节点的距离很好求,可以算出来是 \(\sum_{i = 0}^{n - 1} i * k^i\)
接下来我们考虑第 1 层的一个节点到其它子节点的距离。
若设 \(t\) 为第 0 层节点到其它所有节点的距离和,而第 1 层的节点相比于第 0 层的节点,到 \(a\) 部分节点的距离减少了 1,到 \(b\) 部分节点的距离增加了 1,总距离的变化就是 \(a - b\)

\(a\) 就是一个子树的总点数,可以通过循环去求解,那么 \(b\) 就是树的总点数减去 \(a\)
这样子求出来了每个点到其他点的总距离之和,但是每条边我们计算了两次,所以最后结果要除 2,这里就要用到逆元,因为要先除后取模

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
LL T = 1, n, ans, k, sum, t, s[N];
LL qpow(LL a, LL b){
	if (b == 0) return 1;
	LL ans = 1;
	while (b != 0){
		if (b & 1) ans = (ans * a) % mod;
		b >>= 1;
		a = (a * a) % mod;
	}
	return ans;
}
LL inv(LL x, LL p){//逆元
	return qpow(x, p - 2);
}
void solve(){
	cin >> n >> k;
	//sum 为点数的总和, t 为当前层的值 
	for (LL i = 0; i <= n - 1; i++){
		LL l = qpow(k, i);
		t = (t + (i * l) % mod) % mod;
		sum = (sum + l) % mod;
		s[i] = sum;
	}
	ans = t;
	for (LL i = 2; i <= n; i++){
		LL l = qpow(k, i - 1);
		t = (t + (sum - (s[n - i] * 2) % mod + mod) % mod) % mod;
		ans = (ans + (l * t % mod) % mod) % mod;
	}
	cout << (ans * inv(2, mod)) % mod << "\n";
}
int main(){
//	cin >> T;
	while(T--)
		solve();
	return 0;
}

C.小y的序列

题目大意:

定义一个区间 \([l, r]\) 的美丽值为 \(max(a[i], ..., a[j]) = min(a[i], ..., a[j]) + k (l <= i <= j <= r)\) 的个数。
给定一个长为 \(n\) 的序列以及 \(k\),求出 \([1, n]\) 的美丽值。

思路:

如果固定了左端点,随着右端点的右移,区间最大值减去区间最小值的结果非递减,所以固定左端点,然后二分查找右端点。
先二分找到最大值减去最小值等于 \(k\) 的左端点,判断是否符合条件,若是,再找右端点,计算答案。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e6 + 10;
int n, k, mx[N][21], mn[N][21], a[N];
LL ans;
void init(){
    for (int i = 1; i <= n; i ++ ){
        mx[i][0] = a[i];
        mn[i][0] = a[i];
    }
    int k = log2(n);
    for (int j = 1; j <= k; j ++ )
        for (int i = 1; i + (1 << j) - 1 <= n; i ++ ){
            mx[i][j] = max(mx[i][j - 1], mx[i + ( 1 << (j - 1) )][j - 1]);
            mn[i][j] = min(mn[i][j - 1], mn[i + ( 1 << (j - 1) )][j - 1]);
        }
}
int query(int l, int r){
    int k = log2(r - l + 1);
    return max(mx[l][k], mx[r - (1 << k) + 1][k]) - min(mn[l][k], mn[r - (1 << k) + 1][k]);
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    cin >> n >> k;
    for (int i = 1; i <= n; i ++ )
        cin >> a[i];
    init();
    for (int i = 1; i <= n; i ++ ){
        int l = i, r = n;
        while (l < r){
            int mid = l + r >> 1;
            if (query(i, mid) < k) l = mid + 1;
            else r = mid;
        }
        int p = l;
        if (query(i, p) < k) continue;
        l = i, r = n;
        while (l < r){
            int mid = l + r + 1 >> 1;
            if (query(i, mid) <= k) l = mid;
            else r = mid - 1;
        }
        int q = l;
        ans += q - p + 1;
    }
    cout << ans << "\n";
    return 0;
}

D.小y的质因数

题目大意:

\(T\) 组询问,每次给出三个数 \(l, r, k\),代表询问在区间 \([l, r]\) 之间的数 \(x\) 满足 \(x\) 的质因子个数大于等于 \(log2(x) - k\) 的个数。

思路:

因为 \(l\)\(r\) 的数据范围小于 \(1e12\),同时 \(k\) 最大为 10。在 \(1e12\) 中质因子个数大于等于 \(log2(x) - k\) 的数是有限的。暴力搜出每一个 \(k\) 对应的数,然后二分查找
\(dfs\) 中,只需要搜索到 \(log2(x)\) - 质因子个数等于 10 的就可以停止了,不然就 \(T\) 了。
这样子,最小的质因子就可以求出来了。\(log2(1e12)\) 是 40,差为 10,所以将 11 个 2 合并,即 \(2^{11}\),其它质因子都是 2,可以得到要搜的最大的质因数为 2048,用质数筛预处理一下。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e6 + 10;
LL T, l, r, k;
int prime[N], cnt;
bool st[N];
vector <LL> num[11];
void get_primes(int n){
	st[1] = true;
	for (int i = 2; i <= n; i ++ ){
		if (!st[i]) prime[++ cnt] = i;
		for (int j = 1; j <= cnt && i * prime[j] <= n; j ++ ){
			st[i * prime[j]] = true;
			if (i % prime[j] == 0) break;
		}
	}
}
void dfs(LL x, LL y, LL p){
	if (p < (LL)ceil(log2(x)) - 10) return;
	if (y == cnt + 1){
		num[(LL)ceil(log2(x)) - p].push_back(x);
		return;
	}
	for (int i = 0; x <= 1e12; ++ i){
		dfs(x, y + 1, p + i);
		x *= prime[y];
	}
}
void init(){
	get_primes(2100);
	dfs(1, 1, 0);
	for (int i = 0; i <= 10; i ++ )
		sort(num[i].begin(), num[i].end());
}
void solve(){
	cin >> l >> r >> k;
	LL ans = 0;
	for (int i = 0; i <= k; i ++ )
		ans += upper_bound(num[i].begin(), num[i].end(), r) - lower_bound(num[i].begin(), num[i].end(), l);
	cout << ans << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	init();
	cin >> T;
	while ( T -- )
		solve();
	return 0;
}

E.小y的容器

题意:

\(n\) 个数放到三个容器中,有 \(m\) 个限制,每个限制告诉你 \(x\) 不能放到 \(y\) 容器中,求出每个容器中的数进行排序后相邻两个数之间的差值 <= 3 的放置数字的方案数(每个容器中至少有一个数字)。

思想:

容易想到定义 \(dp[i][a][b][c]\) 为将第 \(i\) 个数放到容器后,第一个容器中最后一个数为 \(a\),第二个容器中最后一个数为 \(b\),第三个容器中最后一个数为 \(c\)
但是这个 \(dp\) 方程的空间大小为 \(n^4\),超限的。
因为相邻两个数的差值不超过 3,所以优化一下,\(dp[i][a][b][c]\) 表示将第 \(i\) 个数放到容器后,第一个容器最后一个数与 \(i\) 的差值为 \(a\),第二个容器最后一个数与 \(i\) 的差值为 \(b\),第三个容器最后一个数与 \(i\) 的差值为 \(c\)
如果数与 \(i - 1\) 的差值为 3,那么对于 \(i\),它的差值一定大于 3 了,所以大于 3 的都可以不用记录,因为对答案没有影响。
特殊定义 \(dp[i][4][4][4]\) 为容器为空的状态,所以 \(dp[0][4][4][4] = 1\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e4 + 10, mod = 1e9 + 7;
LL n, m, dp[N][5][5][5];
bool v[N][4];
LL to(LL x){
	return (x == 4) ? 4 : min(x + 1, 3LL);
}
int main(){
	cin >> n >> m;
	for (int i = 0; i < m; i ++ ){
		LL x, y;
		cin >> x >> y;
		v[x][y] = true;
	}
	dp[0][4][4][4] = 1;
	for (int i = 0; i < n; i ++ ){
		for (int a = 0; a <= 4; a ++ ){
			for (int b = 0; b <= 4; b ++ ){
				for (int c = 0; c <= 4; c ++ ){
					if (a != 3 && !v[i + 1][1])
						dp[i + 1][0][to(b)][to(c)] = (dp[i + 1][0][to(b)][to(c)] + dp[i][a][b][c]) % mod;
					if (b != 3 && !v[i + 1][2])
						dp[i + 1][to(a)][0][to(c)] = (dp[i + 1][to(a)][0][to(c)] + dp[i][a][b][c]) % mod;
					if (c != 3 && !v[i + 1][3])
						dp[i + 1][to(a)][to(b)][0] = (dp[i + 1][to(a)][to(b)][0] + dp[i][a][b][c]) % mod;
				}
			}
		}
	}
	LL ans = 0;
	for (int a = 0; a <= 3; a ++ )
		for (int b = 0; b <= 3; b ++ )
			for (int c = 0; c <= 3; c ++ )
				ans = (ans + dp[n][a][b][c]) % mod;
	cout << ans << "\n";
	return 0;
}
posted on 2022-02-25 13:55  Hamine  阅读(62)  评论(0编辑  收藏  举报