Codeforces Round #697(div3)

A. Odd Divisor

  题意就是判断这个数是否有大于等于3的奇数因子。
  考虑用二进制来表示一个数,可以举例去找规律。(110)2=(6)10(1000)2=(8)10, (1001)2=(9)10,.通过这些例子不难发现只要一个数x的二进制表示下,只要末尾有0,那么它一定可以被2整除,所以如果末尾有0的话,直接右移就可以了,一直到x的二进制表示下最后一位是1的时候停止,此时的x一定是一个奇数,只要判断最后这个x是否等于1就行了。所以总的代码就是

int a; std::cin>>a; while(a % 2 == 0) a /= 2; if(a == 1) puts("NO"); else puts("YES");

但是我们再思考一步,如果没有大于等于3的奇数因子的话,那么就是这个数在一直右移的过程中,最后得到的结果是1,那么它就可以表示成x=12k。基于这个结论,我们可以每次O(1)的判断这个数是不是满足题意得

i64 n; std::cin >> n; std::cout << ((n & (n - 1)) ? "YES\n" : "NO\n");

B. New Year's Number

  题意是让我们判断这个数能不能被若干个2020和若干个2021来表示。
  如果一个数x可以通过题目得意思得到得话,那么就是满足这个式子x=cnt12020+cnt22021,可以转化一下式子,也就是x=cnt12020+cnt2(2020+1),接下来我们合并一下同类项,就可以得到x=(cnt1+cnt2)2020+cnt2,只要我们能够满足(cnt2+cnt1)2020x就可以了

int n; std::cin >> n; int cnt = n / 2020; int res = n - cnt * 2020; std::cout << (res <= cnt ? "YES\n" : "NO\n");

C. Ball in Berland

  题意是给定了男生和女生之间是否能够配对的关系,让我们求出至少能够配成两对的方案数
  可以因为男生和女生存在配对的关系,可以联想到连边的操作,也就是如果uv能够配对成功,就将uv连边。因为只需要找出两对男女就行了,所以可以先固定一对,然后在再看剩下的人中能不能再配对出一对就可以了。对于这样的问题,正面去考虑第二对是否存在的话会比较麻烦,所以考虑正难则反的策略,去考虑此时固定的第一对会影响到哪些对,使这些对能够陪对的男女之间不能配对成功,可以通过uv所连的边来进行表示,选定了u,v的话就会影响到du[u]+du[v]1种关系的,所以选定u,v这一对关系的话,可以得到kdu[u]du[v]+1种关系满足题意。这样去求解的话所有的情况会多算一次,所以最后要除以2.

int n, m, q; std::cin >> n >> m >> q; std::vector<int> a(q), b(q); std::map<int,int> ma, mb; rep(i,0,q) { std::cin >> a[i]; ma[a[i]] ++; } rep(i,0,q) { std::cin >> b[i]; mb[b[i]] ++; } i64 ans = 0; rep(i,0,q) { ans += q - ma[a[i]] - mb[b[i]] + 1; } std::cout << ans / 2 << "\n";

D. Cleaning the Phone

  题意是我们对每一个应用后它们自己相对应得重要程度和内存大小,在至少删除若干个内存大小总和为m的应用后,使得剩余应用的重要程度最大。
  先考虑无解的情况,当所有的内存之和加起来都要小于m的话,那就是无解的

if (std::accumulate(v.begin() + 1, v.end(), 0ll) < m) { std::cout << "-1\n"; return ; }

  接下来就是考虑在有解的前提下,使得重要程度最大了,对于删除应用的选择的话,可以分为四种:
  第一种:在还没有删除的重要程度为1的应用中,占用内存最大的应用内存大于此时的m,直接删掉并且结束循环

if (a[l] >= m) { ans ++; m -= a[l ++ ]; }

  第二种:在第一种情况不成立的前提要,如果重要程度为2的应用中,占用内存最大的应用删除后可以直接让m0那么就删掉它并结束循环

if (b[r] >= m) { ans += 2; m -= b[r ++ ]; }

  第三种:在前两种情况都不满足的前提下,如果现在剩下的重要程度为1的应用的最大值和次大值之和的贡献要小于重要程度为2的应用的话,优先删除重要程度为2的应用

if (b[r] > a[l] + a[l + 1]) { m -= b[r ++ ]; ans += 2; }

  第四种:直接删除重要程度为1的应用

void solve() { int n, m; std::cin >> n >> m; std::vector<i64> v(n + 1); std::vector<int> p(n + 1); for (int i = 1; i <= n; i ++ ) std::cin >> v[i]; for (int i = 1; i <= n; i ++ ) std::cin >> p[i]; if (std::accumulate(v.begin() + 1, v.end(), 0ll) < m) { std::cout << "-1\n"; return ; } std::vector<int> a(n + 1), b(n + 1); int idx = 0, idt = 0; rep(i,1,n + 1) { if (p[i] & 1) a[ ++ idx] = v[i]; else b[ ++ idt] = v[i]; } std::sort(a.begin() + 1, a.begin() + 1 + idx, [&] (int x, int y) { return x > y; }); std::sort(b.begin() + 1, b.begin() + 1 + idt, [&] (int x, int y) { return x > y; }); int l = 1, r = 1; int ans = 0; while ((l != idx + 1 || r != idt + 1) && m > 0) { if (a[l] >= m) { ans ++; m -= a[l ++ ]; } else if (b[r] >= m) { ans += 2; m -= b[r ++ ]; } else if (b[r] > a[l] + a[l + 1]) { m -= b[r ++ ]; ans += 2; } else { ans ++ ; m -= a[l ++ ]; } } std::cout << ans << "\n"; }

E.Advertising Agency

  题意就是在使得签约的博主粉丝数量最多的签约方案有多少种。
  可以将所有的博主按照它们所拥有的粉丝数进行从大到小排序,在排序好了的博主中选择前k名就一定可以达到最大值,现在要考虑就是方案了。因为在a[1k]的序列中,除了最小值以外的所有数都是必须要选上才能使得贡献最大的,所以只需要去考虑最小值的方案选择,那么就只有两种情况了,第一种就是刚好把所有的最小值都包含进了所要的区间中,此时的方案数就是1。第二种就是还有部分的最小值在这个区间外面,那么就从所有的这些数中选出need个那么方案就是(totalneed)

void solve() { int n, k; std::cin >> n >> k; std::vector<int> a(n); for(int i = 0; i < n; i++ ) std::cin >> a[i]; std::sort(a.rbegin(), a.rend()); int mid = a[k - 1]; int cnt = 0, cur = 0; for (int i = 0; i < n; i++ ) cnt += a[i] == mid, cur += (a[i] == mid && i < k); Z ans = binom(cnt, cur); std::cout << ans.val() << "\n"; }

F. Unusual Matrix

  题意是给我们两个01矩阵,判断能不能通过整行异或或者整列异或次操作使得矩阵A和矩阵B相等。
  因为是整行整列的异或,所以我们可以把问题简化到判断每一行的第一列和每一列的第一行是否进行异或操作就行了,可以让矩阵A和矩阵B同时操作,按照两种方式选择是否异或的时候直接判断在该位置上是不是有1,是就异或不是就不异或,这样我们就可以让AB的第一行和第一列相同了,如果这个时候两个矩阵相同就是可以否则不行

void solve() { int n; std::cin >> n; std::vector<std::string> s(n), e(n); rep(i,0,n) std::cin >> s[i]; rep(i,0,n) std::cin >> e[i]; rep(i,0,n) { if (s[i][0] == '1') rep(j,0,n) s[i][j] = s[i][j] ^ '1' ^ '0'; if (e[i][0] == '1') rep(j,0,n) e[i][j] = e[i][j] ^ '1' ^ '0'; } rep(i,0,n) { if (s[0][i] == '1') rep(j,0,n) s[j][i] = s[j][i] ^ '1' ^ '0'; if (e[0][i] == '1') rep(j,0,n) e[j][i] = e[j][i] ^ '1' ^ '0'; } std::cout << (s == e ? "YES\n" : "NO\n"); }

G. Strange Beauty

  题意是给我们一个序列a,要满足在这个序列中,任意一个数ai满足小于它的所有数都能够整除ai。问最少需要移走多少个元素能够使得序列满足题意
  因为要让删除的次数最小,那么就是求出在这个序列中拥有除数最多的那个数的它有包含的除数个数, 然后用n减去就可以了。我们可以用一个数去更新它的所有倍数,也就是dp[ik]=max(dp[i],dp[ik]).

void solve() { int n; std::cin >> n; std::vector<int> a(n); for (int i = 0; i < n; i ++ ) std::cin >> a[i]; int N = *max_element(all(a)); std::vector<int> cnt(N + 1), dp(N + 1); for (int i = 0; i < n; i ++ ) cnt[a[i]] ++; for (int i = 1; i <= N; i ++ ) { dp[i] += cnt[i]; for (int j = 2 * i; j <= N; j += i ) dp[j] = std::max(dp[j], dp[i]); } std::cout << n - *max_element(all(dp)) << "\n"; }

__EOF__

本文作者HoneyGrey
本文链接https://www.cnblogs.com/Haven-/p/16220917.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   浅渊  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示