2023牛客第六场补题报告A B C E G

2023牛客第六场补题报告A B C E G

A-Tree_2023牛客暑期多校训练营6 (nowcoder.com)

思路

可以考虑先进行重构树然后再进行树上dp进行状态转移。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e3+10;
const int inf = 1e18;
int a[N],c[N],fa[N],siz[N];
int dp[N][N];
int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
void solve(){
    int n;  cin>>n;
    for(int i = 1;i<=n;i++)  cin>>a[i];
    for(int i = 1;i<=n;i++)  cin>>c[i];
    vector<vector<int>>edge;
    for(int i = 1;i<n;i++){
        int u,v,w;  cin>>u>>v>>w;
        edge.push_back({w,u,v});
    }
    sort(edge.begin(),edge.end());
    for(int i = 1;i<=n;i++){
        siz[i] = 1;  fa[i] = i;
        dp[i][a[i]] = 0;
        dp[i][a[i]^1] = -c[i];
    }
    for(auto e:edge){
        int u = e[1],v = e[2],w = e[0];
        u = find(u),v = find(v);
        vector<int>tmp(siz[u]+siz[v]+1,-inf);
        for(int j = 0;j<=siz[u];j++){
            for(int k = 0;k<=siz[v];k++){
                tmp[k+j] = max(tmp[j+k],dp[u][j]+dp[v][k]+1ll*j*(siz[v]-k)*w+1ll*(siz[u]-j)*k*w);
            }
        }
        fa[v]=u;
        siz[u]+=siz[v];
        for(int j = 0;j<=siz[u];j++)dp[u][j]=tmp[j];
    }
    int ans = 0;
    int root = find(1);
    for(int i = 0;i<=n;i++)ans = max(ans,dp[root][i]);
    cout<<ans<<'\n';
}
signed main(){
    solve();
    return 0;
}

B-Distance_2023牛客暑期多校训练营6 (nowcoder.com)

思路

很好想到是暴力枚举两端直接计算每个数对对答案的贡献次数,但是需要注意一个点就是如果直接暴力跑是一个 n 3 n^3 n3的复杂度,但是我们有公式,只要预处理出来所有的组合数就可以将内层的一个n优化为O(1)。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 998244353;
typedef pair<int, int> PII;
int n;

int qpow(int a, int b) {
  int ans = 1, base = a;
  while (b) {
    if (b & 1) ans = ans * base % mod;
    base = base * base % mod;
    b >>= 1;
  }
  return ans % mod;
}
int k;
int fact[N];
int infact[N];
void init() {
  fact[0] = 1;
  infact[0] = 1;
  for (int i = 1; i < N; i++) {
    fact[i] = (fact[i - 1] * i) % mod;
  }
  infact[N - 1] = qpow(fact[N - 1], mod - 2);
  for (int i = N - 2; i; i--) {
    infact[i] = infact[i + 1] * (i + 1) % mod;
  }
}
int C(int a, int b) {
  if (a < b) return 0;
  return (fact[a] * (infact[b] * infact[a - b] % mod)) % mod;
}  //预处理阶乘,逆元求组合数
void solve() {
  cin >> n;
  vector<int> v1(n + 1), v2(n + 1);
  for (int i = 1; i <= n; i++) {
    cin >> v1[i];
  }
  for (int i = 1; i <= n; i++) {
    cin >> v2[i];
  }
  sort(v1.begin() + 1, v1.end());
  sort(v2.begin() + 1, v2.end());

  int res = 0;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      int l = C(i + j - 2, min(i - 1, j - 1));
      // for (int k = 0; k <= min(i - 1, j - 1); k++) {
      // l += C(i - 1, k) * C(j - 1, k);
      // l %= mod;
      // }
      int r = C(n + n - i - j, min(n - i, n - j));
      // for (int k = 0; k <= min(n - i, n - j); k++) {
      // r += C(n - i, k) * C(n - j, k);
      // r %= mod;
      // }
      res += (l * r % mod) * abs(v1[i] - v2[j]) % mod;
      res %= mod;
    }
  }
  cout << res << "\n";
}

signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  init();
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

C-idol!!_2023牛客暑期多校训练营6 (nowcoder.com)

思路

我们打一个表就可以发现,其实每个含有5的倍数其实都是一个等差数列,所以直接枚举5的整数次幂然后使用求和公式相加即可,注意需要使用__int128答案可能会爆long long。

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve();
signed main() {
  // cin.sync_with_stdio(0);
  // cin.tie(0);
  int T = 1;
  // cin >> T;
  while (T--) {
    solve();
  }
  return 0;
}
void print(__int128 x) {
  if (x < 0) putchar('-'), x = -x;
  if (x > 9)
    print(x / 10);  //注意这里是x>9不是x>10 (2019.10 wa哭了回来标记一下)
  putchar(x % 10 + '0');
  // putchar('\n');
}
__int128 df(int n) {
  __int128 res = 0;
  __int128 mul = 5;
  while (mul <= n) {
    //枚举mul
    __int128 h = n / 2 - mul / 2;
    __int128 cnt = (n / mul - 1) / 2 + 1;
    res += (h + h - mul * (cnt - 1)) * cnt / 2;
    // print(h);
    // print(cnt);
    // print(mul);
    // putchar('\n');
    // //枚举mul * 2
    mul *= 2;
    h = n / 2 - (mul - 1) / 2;
    cnt = (n / mul);
    mul /= 2;
    res += (h + h - mul * (cnt - 1)) * cnt / 2;

    // print(h);
    // print(cnt);
    // print(mul);
    // cout << "****\n";
    mul *= 5;
  }
  return res;
}
__int128 dfo(int n) {
  __int128 res = 0;
  __int128 mul = 5;
  while (mul <= n) {
    //枚举mul
    res += (n / mul - 1) / 2 + 1;
    mul *= 5;
  }
  return res;
}

void solve() {
  int n;
  cin >> n;
  __int128 ans = df(n - (n & 1));
  if (n & 1) {
    ans += dfo(n);
  }
  print(ans);
}

E-Sequence_2023牛客暑期多校训练营6 (nowcoder.com)

思路

其实只需要分类讨论奇偶的情况,判断在一段中最多有多少个和为偶数的连续段,只要是大于等于k的就一定可行。但是这题比较复杂的一点是比较绕,很容易判断错误。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

template <typename T>
struct Fenwick {
	int n;
	vector<T> a;
	Fenwick(int n) : n(n), a(n + 10) {}
	void add(int x, T v) {
		for (int i = x; i <= n; i += i & -i) {
			a[i] += v;
		}
	}
	T sum(int x) {
		T ans = 0;
		for (int i = x; i; i -= i & -i) {
			ans += a[i];
		}
		return ans;
	}
	T rangeSum(int l, int r) { return sum(r) - sum(l - 1); }
	int kth(T k) {
		int x = 0;
		for (int i = 1 << std::__lg(n); i; i /= 2) {
			if (x + i <= n && k >= a[x + i - 1]) {
				x += i;
				k -= a[x - 1];
			}
		}
		return x;
	}
};
int ji[N],ou[N];
void solve() {
	int q;
	cin >> n >> q;
	Fenwick<int> bi(n);
	fill(ji,ji+n+1,0);
	fill(ou,ou+1+n,0);
	vector<int> place_1;
	for (int i = 1; i <= n; i++) {
		int x;
		cin >> x;
		a[i] = x % 2;
		if(a[i]) place_1.push_back(i);
		bi.add(i, x % 2);
	}
	vector<int> ma(n + 1);
	for(int i = 1,len = 0;i <= n;i ++) {
		if(a[i] == 1) {
			ma[i] = ++len;
			
		}
	}
	for(int i = 1,j = 0,k = 0,start;i <= n;i ++){
		ji[i] += ji[i-1];
		if(a[i] == 1 && j == 0) {
			k = 0;
			j = 1;
			start = i;
		}
		else if(a[i] == 1 && j == 1) {
			k++;
			for(int ll = start;ll <= i;ll ++) ji[ll] += k;
			j = 0;
		}
		if(j == 1){
			k++;
		}
	}
	for(int i = 1,j = 0,k = 0,start,not_first = 0;i <= n;i ++){
		ou[i] += ou[i-1];
		if(a[i] == 1) {
			if(not_first == 0) {
				not_first = 1;
				continue;
			}
		}
		if(a[i] == 1 && j == 0) {
			k = 0;
			j = 1;
			start = i;
		}
		else if(a[i] == 1 && j == 1) {
			k++;
			for(int ll = start;ll <= i;ll ++) ou[ll] += k;
			j = 0;
		}
		if(j == 1){
			k++;
		}
	}
	//for(int i = 1;i <= n;i ++) cout << ou[i] << " ";cout << endl;
	
	while (q--) {
		int l, r, k;
		cin >> l >> r >> k;
		
		int tmp = bi.rangeSum(l, r);
		if (tmp % 2 == 0 && r - l + 1 >= k) {
			if(tmp == 0) {
				cout << "YES" << endl;
				continue;
			}
			int pla_1 = lower_bound(place_1.begin(),place_1.end(),l) - place_1.begin();
			pla_1 = place_1[pla_1];
			if(ma[pla_1] % 2) {
				int sum = ji[r] - ji[l - 1];
				int num = (r - l + 1) - sum + tmp / 2;
				if(num >= k) {
					cout << "YES" << endl;
				} else {
					cout << "NO" << endl;
				}
			} else {
				int sum = ou[r] - ou[l - 1];
				int num = (r - l + 1) - sum + tmp / 2;
				if(num >= k) {
					cout << "YES" << endl;
				} else {
					cout << "NO" << endl;
				}	
			}
		} else
			cout << "NO\n";
	}
}

signed main() {
	IOS;
	int t = 1;
	cin >> t;
	for (int i = 1; i <= t; i++) {
		solve();
	}
}

G-Gcd_2023牛客暑期多校训练营6 (nowcoder.com)

思路

我们可以观察到,其实z一定要是x,y最大公约数的倍数。

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define fi first
#define sc second

using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() {
  int x, y, z;
  cin >> x >> y >> z;
  x = abs(x);
  y = abs(y);
  z = abs(z);
  if (x > y) swap(x, y);
  if (x == 0) {
    if (z != y && z != 0)
      cout << "NO\n";
    else
      cout << "YES\n";
  } else {
    if (z % __gcd(x, y) == 0 && z != 0)
      cout << "YES\n";
    else
      cout << "NO\n";
  }
}

signed main() {
  IOS;
  int t = 1;
  cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值