Codeforces Round 1006 (Div. 3)


A. New World, New Me, New Array

题意:你要选n个值域在[p,p]之间数, 使得总和恰好为k

kk都是一样的,那么令k=|k|,每次填min(k,p),然后k=kmin(k,p)。就能得到k。无解的情况就是n×p<k

点击查看代码
void solve() {
    int n, k, p;
    std::cin >> n >> k >> p;
    k = std::abs(k);
    if (p * n < k) {
    	std::cout << -1 << "\n";
    	return;
    }

    std::cout << (k + p - 1) / p << "\n";
}

B. Having Been a Treasurer in the Past, I Help Goblins Deceive

题意:一个字符串分为两种字符:'-'和'_'。你可以重排字符串,使得子序列"-_-"最多。

我们应该让'-'放两边,中间放'_'。两边'-'的数量应该越接近越好。

点击查看代码
void solve() {
	int n;
	std::cin >> n;
	std::string s;
	std::cin >> s;
	i64 a = std::count(s.begin(), s.end(), '-');
	i64 b = std::count(s.begin(), s.end(), '_');

	i64 c = a / 2;
	std::cout << c * (a - c) * b << "\n";
}

C. Creating Keys for StORages Has Become My Main Skill

题意:你要构造一个数组,使得所有数的或值等于x,并且使得mex最大。

0n1找最大的前缀或和等于x的,那么前面填这些数,后面的都填x就行。

点击查看代码
void solve() {
    int n, x;
    std::cin >> n >> x;
    if (n == 1) {
    	std::cout << x << "\n";
    	return;
    }

    std::vector<int> ans(n);
    int sum = 0, max = 0, val = 0;
    for (int i = 0; i < n; ++ i) {
    	sum |= i;
    	if ((sum & x) == sum) {
    		max = i;
    		val = sum;
    	}
    }

    if (max == n - 1 && (val & x) != x) {
    	-- max;
    }

    int i = 0;
    while (i < n && max >= 0) {
    	ans[i] = max -- ;
    	++ i;
    }

    if (i < n) {
    	for (int j = i; j < n; ++ j) {
    		ans[j] = x;
    	}
    }

    for (int i = 0; i < n; ++ i) {
    	std::cout << ans[i] << " \n"[i == n - 1];
    }
}

D. For Wizards, the Exam Is Easy, but I Couldn't Handle It

题意:左移数组的一个区间,使得逆序对最小。

左移一次相当于把i插到j的后面,对[i+1,j]和除i外的数没有影响。只需要计算这些数和i对逆序对的影响。那么我们枚举i,然后枚举j,暴力即可。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);	
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    int sum = 0;
    for (int i = 0; i < n; ++ i) {
    	for (int j = i + 1; j < n; ++ j) {
    		if (a[i] > a[j]) {
    			++ sum;
    		}
    	}
    }

    int l = 0, r = n - 1;
    int ans = sum;
    for (int i = 0; i < n; ++ i) {
    	int v = sum;
    	for (int j = i; j < n; ++ j) {
    		if (a[j] < a[i]) {
    			-- v;
    		} else if (a[j] > a[i]) {
    			++ v;
    		}

    		if (v < ans || (v == ans && r - l > j - i)) {
    			ans = v;
    			l = i, r = j;
    		}
    	}
    }

    std::cout << l + 1 << " " << r + 1 << "\n";
}

E. Do You Love Your Hero and His Two-Hit Multi-Target Attacks?

题意:构造不超过500个点,使得欧几里得距离等于曼哈顿距离的点对恰好为k个。

这样的点对的x轴或者y轴一定相同,如果有nx轴相同的,就有n(n1)2的贡献,那么我们一行一行的放,一直到贡献满足k就行了,注意每次放完一行列坐标得移到上一行最后的右边。

点击查看代码
void solve() {
    int k;
    std::cin >> k;
    std::vector<std::pair<int, int>> ans;
    int x = -1e9, y = -1e9;
    while (k) {
    	int z = 0;
    	while ((i64)z * (z + 1) / 2 <= k) {
    		++ z;
    	}

    	k -= z * (z - 1) / 2;
    	for (int i = 1; i <= z; ++ i, ++ x) {
    		ans.push_back({x, y});
    	}

    	y += 1;
    }

    std::cout << ans.size() << "\n";
    for (auto & [x, y] : ans) {
    	std::cout << x << " " << y << "\n";
    }
}

F. Goodbye, Banker Life

题意:f[1][1]=kf[i][j]=f[i1][j]f[i1][j1]。求第n行的值。

这题也是人类智慧,不过其实还是有理论的。
感觉递推式应该和杨辉三角有关系,打表发现如果杨辉三角等于位置的数是奇数,那么值就是k,否则是0。那么就变成了求解C(n1,i)是奇数还是偶数。根据Lucas定理,在模运算下我们求解C(n,k),对于一个质数p,可以把n,k分解为p进制数,那么答案就是p进制下对应数做组合数然后每一位的值乘起来。那么发现,如果2进制下n的第inik的第iki,如果ki>ni,那么值就是0,否则就是1,这意味着k的二进制表示下的1必须都在n里出现,即n&k=k

点击查看代码
void solve() {
    int n, k;
    std::cin >> n >> k;
    
    for (int i = 0; i < n; ++ i) {
        std::cout << (((n - 1) & i) == i ? k : 0) << " \n"[i == n - 1];
    }
}

G. I've Been Flipping Numbers for 300 Years and Calculated the Sum

题意:f(n,k)定义为n转换为k进制翻转后再转回10进制的值,求i=1kf(n,i)

发现当k>n时,其在k进制下只有一位数,那么翻转后不变。那么我们讨论nk的情况。
观察数据范围我们得知需要不超过(n)的时间复杂度。那么这提示我们数论分块。
对于i(n),我们暴力就行。
对于i>(n),我们发现ni进制下只有两位数,因为第三位代表i2,而n没有这么大。然后发现第i0的系数是n%ii1的系数是nini进制的两位就表示为(ni,n%i),翻转后就是(n%i,ni)。那么有一个经典结论,对于一个区间[l,r],其中任意一个i[l,r]都有nl=ni,那么对于从lrn对它们的余数是一个等差序列,首项为a=n%l,公差为d=nl。,则我们求的是i=lr(a(il)×d)×i+d=(rl+1)×d+i=lra×i(i2i×l)×d。那么我们只需要计算出sum1=i=lri,sum2=i=lri2,结果就是(rl+1)×d+sum1×a(sum2sum1×l)×d

代码省略了取模类。

点击查看代码
void solve() {
    int n;
    i64 k;
    std::cin >> n >> k;

    auto get = [&](int n, int k) -> Z {
    	std::vector<int> a;
    	while (n) {
    		a.push_back(n % k);
    		n /= k;
    	}

    	Z res = 0;
    	for (auto & x : a) {
    		res = res * k + x;
    	}

    	return res;
    };

    Z ans = 0;
    if (k > n) {
    	ans += (Z)(k - n) * n;
    	k = n;
    }

    auto s1 = [&](i64 n) -> i64 {
        return n * (n + 1) / 2;
    };

    auto s2 = [&](i64 n) -> i64 {
        return n * (n + 1) * (2 * n + 1) / 6;
    };

    auto sum1 = [&](i64 l, i64 r) -> i64 {
        return s1(r) - s1(l - 1);
    };

    auto sum2 = [&](i64 l, i64 r) -> i64 {
        return s2(r) - s2(l - 1);
    };

    for (i64 l = 2, r; l <= k; l = r + 1) {
        if (l * l <= n) {
            r = l;
            ans += get(n, l);
        } else {
            r = std::min(k, n / (n / l));
            i64 a = n % l, d = n / l;
            ans += (Z)a * sum1(l, r) - (sum2(l, r) - sum1(l, r) * l) * d + (Z)d * (r - l + 1);
        }
    }

    std::cout << ans << "\n";
}
posted @   maburb  阅读(315)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示