2022河南萌新联赛第(三)场:河南大学
A-玉米大炮
二分一个时间,然后计算每门大炮可以射击的次数
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
void solve() {
int n,m;
cin>>n>>m;
vector<int>a(n),b(n);
for(int i=0;i<n;++i)cin>>a[i]>>b[i];
int l=0,r=1e18,x;
auto check=[&](int s){
__int128 ans=0;
for(int i=0;i<n;++i){
__int128 c=s/b[i]+1;
ans+=a[i]*c;
}
return ans>=(__int128)m;
};
while(l<=r){
int mid=l+r>>1;
if(check(mid))r=mid-1,x=mid;
else l=mid+1;
}
cout<<x;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
// cin>>t;
while(t--){
solve();
}
return 0;
}
B-逆序对计数
因为长度比较小,所以直接预处理每个区间的逆序对个数,翻转区间只会导致区间内的逆序对数量发生改变。
预处理就对前缀反复的做逆序对即可。
#include <bits/stdc++.h>
using namespace std;
// #define endl '\n'
//#define inf 1e18
typedef long long ll;
typedef __int128 lll;
typedef pair<ll, ll> P;
#define x first
#define y second
#define pi 3.14159265358
#define int long long
const int p = 1e9 + 7;
const int pp = 998244353;
int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, -1, 1};
int ddx[8] = {1, 1, 2, 2, -1, -1, -2, -2}, ddy[8] = {2, -2, 1, -1, 2, -2, 1, -1};
ll ksm(ll a, ll b, ll p) {
ll ans = 1;
while(b) {
if(b & 1) ans = (ans * a) % p;
b >>= 1;
a = (a * a) % p;
}
return ans % p;
}
std::mt19937 rng; // 随机数生成器
int rand(int l, int r) {
std::uniform_int_distribution<int> distribution(l, r);
return distribution(rng);
}
class BIT {
public:
BIT(int size) : size_(size), tree_(size + 1, 0) {}
void update(int index, int delta) {
for (int i = index + 1; i <= size_; i += (i & -i)) {
tree_[i] += delta;
}
}
int query(int index) {
int sum = 0;
for (int i = index + 1; i > 0; i -= (i & -i)) {
sum += tree_[i];
}
return sum;
}
int queryRange(int left, int right) {
return query(right) - query(left - 1);
}
private:
int size_;
vector<int> tree_;
};
const int N = 6005;
int n;
int a[N], f[N][N];
void solve() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
for(int i = n; i; i--) {
BIT b(n + 1);
for(int j = i + 1; j <= n; j++) {
b.update(a[j], 1);
f[i][j] = b.query(a[i]);
f[i][j] += f[i + 1][j];
}
}
// for(int i = 1; i <= n; i++) {
// for(int j = 1; j <= n; j++) {
// cout << f[i][j] << " \n"[j == n];
// }
// }
int ans = f[1][n];
int q;
cin >> q;
while(q -- ) {
int l, r;
cin >> l >> r;
int len = (r - l + 1);
cout << ((ans - f[l][r]) + (len * (len - 1) >> 1) - f[l][r]) << endl;
}
}
/*
*/
signed main () {
// init(minp, primes, m); // primes
// init();
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while(_ -- ) {
solve();
}
return 0;
}
C-区间操作
其实\(f(x)\)就是求质因数分解后有多少个质因数,而opt1是求\(f(\sum b_i)\),所以直接存储每个数的质因数个数即可,题目转换为了区间修改,区间求和。套一个线段树的模板即可。
#include <bits/stdc++.h>
using namespace std;
// #define endl '\n'
//#define inf 1e18
typedef long long ll;
typedef __int128 lll;
typedef pair<ll, ll> P;
#define x first
#define y second
#define pi 3.14159265358
#define int long long
const int p = 1e9 + 7;
const int pp = 998244353;
int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, -1, 1};
int ddx[8] = {1, 1, 2, 2, -1, -1, -2, -2}, ddy[8] = {2, -2, 1, -1, 2, -2, 1, -1};
ll ksm(ll a, ll b, ll p) {
ll ans = 1;
while(b) {
if(b & 1) ans = (ans * a) % p;
b >>= 1;
a = (a * a) % p;
}
return ans % p;
}
std::mt19937 rng; // 随机数生成器
int rand(int l, int r) {
std::uniform_int_distribution<int> distribution(l, r);
return distribution(rng);
}
class SegmentTree {
public:
SegmentTree(vector<int>& nums) {
n = nums.size() - 1;
tree.resize(4 * n + 1);
lazy.resize(4 * n + 1);
build(nums, 1, 1, n);
}
void build(vector<int>& nums, int i, int start, int end) {
if (start == end) {
tree[i] = nums[start];
return;
}
int mid = (start + end) / 2;
build(nums, 2 * i, start, mid);
build(nums, 2 * i + 1, mid + 1, end);
tree[i] = tree[2 * i] + tree[2 * i + 1];
}
void push_up(int i, int start, int end) {
tree[i] = tree[2 * i] + tree[2 * i + 1];
}
void push_down(int i, int start, int end) {
if (lazy[i] != 0) {
int mid = (start + end) / 2;
lazy[2 * i] += lazy[i];
lazy[2 * i + 1] += lazy[i];
tree[2 * i] += lazy[i] * (mid - start + 1);
tree[2 * i + 1] += lazy[i] * (end - mid);
lazy[i] = 0;
}
}
void update(int i, int start, int end, int s, int e, int val) {
if (s <= start && end <= e) {
tree[i] += val * (end - start + 1);
lazy[i] += val;
return;
}
push_down(i, start, end);
int mid = (start + end) / 2;
if (s <= mid) update(2 * i, start, mid, s, e, val);
if (e > mid) update(2 * i + 1, mid + 1, end, s, e, val);
push_up(i, start, end);
}
int query(int i, int start, int end, int s, int e) {
if (s <= start && end <= e) return tree[i];
push_down(i, start, end);
int mid = (start + end) / 2;
int count = 0;
if (s <= mid) count += query(2 * i, start, mid, s, e);
if (e > mid) count += query(2 * i + 1, mid + 1, end, s, e);
return count;
}
void updateRange(int s, int e, int val) {
update(1, 1, n, s, e, val);
}
int queryRange(int s, int e) {
return query(1, 1, n, s, e);
}
private:
int n;
vector<int> tree;
vector<int> lazy;
};
const int m = 4e6;
vector<int> minp(m + 10), primes;
void init(vector<int> & minp, vector<int> & primes, int ma) {
for(int i = 2; i <= ma; i++) {
if(!minp[i]) {
minp[i] = i;
primes.emplace_back(i);
}
for(auto & p : primes) {
if(i * p > ma) break;
minp[i * p] = p;
if(p == minp[i]) break;
}
}
}
int n, q;
vector<int> a;
int f(int x) {
int ans = 0;
while(x > 1) {
x /= minp[x];
ans ++ ;
}
return ans;
}
void solve() {
cin >> n;
a = vector<int>(n + 1);
for(int i = 1, x; i <= n; i++) {
cin >> x;
while(x > 1) {
a[i] ++ ;
x /= minp[x];
}
}
SegmentTree tr(a);
cin >> q;
while(q -- ) {
int op, l, r;
cin >> op >> l >> r;
if(op == 1) {
cout << tr.queryRange(l, r) << endl;
}
else {
int w;
cin >> w;
tr.updateRange(l, r, f(w));
}
}
}
/*
*/
signed main () {
init(minp, primes, m); // primes
// init();
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while(_ -- ) {
solve();
}
return 0;
}
D-小蓝的新技能
首先一个引理是
\[\gcd(x^3,y^3) = gcd(x,y)^3
\]
所以根据题目,我们可以得出
\[(ab)^3 = gcd(a,b)^3(n - \gcd(a,b)^3)
\]
并且当\(b\)取最小值\(1\)时,可以得到\(a^3=n\),所以\(a^3 \le 10^5\)
所以可以暴力的枚举\(a\),然后枚举\(a\)的因子做\(\gcd(a,b)\),然后带入上式反解出\(b\),然后只需要判断\(b\)是否合法即可。
#include <bits/stdc++.h>
using namespace std;
// #define endl '\n'
//#define inf 1e18
typedef long long ll;
typedef __int128 lll;
typedef pair<ll, ll> P;
#define x first
#define y second
#define pi 3.14159265358
#define int long long
const int p = 1e9 + 7;
const int pp = 998244353;
int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, -1, 1};
int ddx[8] = {1, 1, 2, 2, -1, -1, -2, -2}, ddy[8] = {2, -2, 1, -1, 2, -2, 1, -1};
ll ksm(ll a, ll b, ll p) {
ll ans = 1;
while(b) {
if(b & 1) ans = (ans * a) % p;
b >>= 1;
a = (a * a) % p;
}
return ans % p;
}
std::mt19937 rng; // 随机数生成器
int rand(int l, int r) {
std::uniform_int_distribution<int> distribution(l, r);
return distribution(rng);
}
vector<int> d[201010];
int n;
void init() {
for(int i = 1; i <= 2e5; i++) {
for(int j = i; j <= 2e5; j += i) {
d[j].emplace_back(i);
}
}
}
int sqrt(int x) {
int l = 0, r = 1e5;
while(l < r) {
int mid = (l + r + 1) >> 1;
if(mid * mid * mid <= x) l = mid;
else r = mid - 1;
}
if(l * l * l != x) return -1;
return l;
}
void solve() {
cin >> n;
int ans = 0;
for(int a = 1; a <= 1e5; a++) {
for(auto & g : d[a]) {
int m = n - g * g * g;
int sq = sqrt(m);
if(sq == -1) continue;
// cout << "g : " << g << endl;
// cout << "l3 : " << m << ", sq : " << sq << endl;
int ab = sq * g;
// cout << ab << endl;
if(ab > 0 && ab % a == 0 && g * g * g + sq * sq * sq == n && __gcd(a, ab / a) == g) {
// cout << "a : " << a << ", b : " << ab / a << endl;
ans ++ ;
break;
}
}
}
cout << ans << endl;
}
/*
*/
signed main () {
// init(minp, primes, m); // primes
init();
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;
// cin >> _;
while(_ -- ) {
solve();
}
return 0;
}
E-演算任务
其实就是简单的背包问题,\(f[i][j][0/1]\)前\(i\)个数组合出\(j\)有没有使用除2的最小花费。
难点其实是第二位可能是负数,所以要偏移一下。
#include<bits/stdc++.h>
using namespace std;
using vi = vector<int>;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
//#define int i64
using pii = pair<int, int>;
using vii = vector<pii>;
const int inf = 1e9, INF = LLONG_MAX;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, x;
cin >> n >> x;
int N = abs(x) + n * 100;
vector f(2, vector(2, vi(N * 2 + 1, inf)));
f[0][0][0 + N] = 0;
int i = 1;
for (int v; n; n--, i ^= 1) {
cin >> v;
for (int j = -N, t; j <= N; j++) {
t = j + v;
if (-N <= t and t <= N) {
f[i][0][t + N] = min(f[i ^ 1][0][t + N], f[i ^ 1][0][j + N] + 1);
f[i][1][t + N] = min(f[i ^ 1][1][t + N], f[i ^ 1][1][j + N] + 1);
}
t = (j + v) / 2;
if (-N <= t and t <= N) {
f[i][1][t + N] = min({f[i][1][t + N], f[i ^ 1][1][t + N], f[i ^ 1][0][j + N] + 1});
}
}
}
int res = min(f[i ^ 1][0][x + N], f[i ^ 1][1][x + N]);
if (res == inf) res = -1;
cout << res << "\n";
return 0;
}
F-爱学习的小蓝
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
using i128 = __int128;
const int inf = INT_MAX, INF = LLONG_MAX;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;
vector t = {2, 8, 8, 18, 18, 32, 32};
void solve() {
int n, res = 0;
cin >> n;
for (const auto i: t) {
res++;
n -= i;
if (n <= 0)break;
}
cout << res << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int TC;
for (cin >> TC; TC; TC--)
solve();
return 0;
}
H-树上问题
换根dp
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef long long ll;
typedef pair<ll, ll> P;
#define int long long
int n;
vector<vector<int>> g;
vector<int> a, val, son, mx, val2;
int dfs1(int u, int fa) {
for(auto & ne : g[u]) {
if(ne == fa) continue;
int d = dfs1(ne, u) + a[ne];
if(d > val[u]) {
val2[u] = val[u];
val[u] = d;
son[u] = ne;
}
else if(d > val2[u]) {
val2[u] = d;
}
}
return val[u];
}
void dfs2(int u, int fa, int now) {
mx[u] = max(val[u], now) + a[u];
for(auto & ne : g[u]) {
if(ne == fa) continue;
if(ne == son[u]) { // 重儿子
dfs2(ne, u, max(now, val2[u]) + a[u]);
}
else {
dfs2(ne, u, max(now, val[u]) + a[u]);
}
}
}
signed main () {
cin >> n;
mx = son = val = val2 = a = vector<int>(n + 1);
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
g = vector<vector<int>>(n + 1);
for(int i = 0, u, v; i < n - 1; i++) {
cin >> u >> v;
g[u].emplace_back(v);
g[v].emplace_back(u);
}
dfs1(1, 0);
dfs2(1, 0, 0);
int ans = 0;
for(int i = 1; i <= n; i++) {
int d1 = 0, d2 = 0;
for(auto & ne : g[i]) {
if(mx[ne] > d1) {
d2 = d1;
d1 = mx[ne];
}
else if(mx[ne] > d2) {
d2 = mx[ne];
}
}
ans = max(ans, d1 + d2 + mx[i]);
}
cout << ans << endl;
return 0;
}
I-旅行
把点分成\((x,0/1)\)表示在\(x\)点有没有做核酸,然后不能连续经过两个0,因此建图
\[((u,0),(v,1),w+x)\\
((u,1),(v,0),w)\\
((u,1),(v,1),w+2)
\]
以及他们的反向边,然后跑最短路就行
#include<bits/stdc++.h>
using namespace std;
#define int long long
using vi = vector<int>;
using i32 = int32_t;
using pii = pair<int, int>;
using vii = vector<pii>;
using i128 = __int128;
const int inf = INT_MAX, INF = LLONG_MAX;
const int mod = 1e9 + 7;
const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
using edge = array<int, 3>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, m, x;
cin >> n >> m >> x;
vi dis(n * 2 + 1, INF);
dis[1] = 0;
priority_queue<pii, vector<pii>, greater<pii>> q;
q.emplace(0, 1);
vector<vector<pii>> e(n * 2 + 1);
for (int u, v, w; m; m--) {
cin >> u >> v >> w;
e[u].emplace_back(v + n, w + x);
e[u + n].emplace_back(v, w);
e[u + n].emplace_back(v + n, w + x);
e[v].emplace_back(u + n, w + x);
e[v + n].emplace_back(u, w);
e[v + n].emplace_back(v + n, w + x);
}
vi vis(n * 2 + 1);
while (not q.empty()) {
auto [d, u] = q.top();
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto [v, w]: e[u]) {
if (vis[v] or d + w >= dis[v]) continue;
dis[v] = d + w;
q.emplace(dis[v], v);
}
}
cout << min(dis[n], dis[n + n]) << "\n";
return 0;
}
J-神奇数字
任意两个数差值的gcd就是答案
#include <bits/stdc++.h>
using namespace std;
// #define endl '\n'
//#define inf 1e18
typedef long long ll;
typedef __int128 lll;
typedef pair<ll, ll> P;
#define x first
#define y second
#define pi 3.14159265358
#define int long long
const int p = 1e9 + 7;
const int pp = 998244353;
int dx[8] = {-1, 0, 1, 0, -1, -1, 1, 1}, dy[8] = {0, 1, 0, -1, -1, 1, -1, 1};
int ddx[8] = {1, 1, 2, 2, -1, -1, -2, -2}, ddy[8] = {2, -2, 1, -1, 2, -2, 1, -1};
ll ksm(ll a, ll b, ll p) {
ll ans = 1;
while(b) {
if(b & 1) ans = (ans * a) % p;
b >>= 1;
a = (a * a) % p;
}
return ans % p;
}
std::mt19937 rng; // 随机数生成器
int rand(int l, int r) {
std::uniform_int_distribution<int> distribution(l, r);
return distribution(rng);
}
vector<int> d[201010];
void init () {
for(int i = 1; i <= 2e5; i++) {
for(int j = i; j <= 2e5; j += i) {
d[j].emplace_back(i);
}
}
}
void solve() {
int a[3] = {};
for(int i = 0; i < 3; i++) {
cin >> a[i];
}
sort(a, a + 3);
int g = 0;
for(int i = 0; i < 3; i++) {
for(int j = i + 1; j < 3; j++) {
g = __gcd(g, a[j] - a[i]);
}
}
// cout << g << endl;
if(g == 0) cout << -1 << endl;
else {
for(auto & x : d[g]) {
cout << x << " ";
}
cout << endl;
}
}
/*
*/
signed main () {
// init(minp, primes, m); // primes
init();
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
while(_ -- ) {
solve();
}
return 0;
}
L-合成游戏
找规律
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=1e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
int fac[N];
int f[N];
int ksm(int a,int b){
int res=1;
while(b){
if(b&1)res=res*a%Mod;
b>>=1;
a=a*a%Mod;
}
return res;
}
void init(){
fac[0]=f[0]=1;
int c=ksm(2,Mod-2);
for(int i=1;i<=1e5;++i){
fac[i]=fac[i-1]*i%Mod;
f[i]=f[i-1]*c%Mod;
}
}
void solve() {
int n;
cin>>n;
int ans=fac[n];
while(n>1){
n/=2;
ans=ans*f[n]%Mod;
}
cout<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
init();
while(t--){
solve();
}
return 0;
}