ABC191小结-水

整体来讲挺水的。随便记录两道题吧。

C.Digital Graffiti
题目大意:

二维01矩阵,给你一个多边形。问你它有多少条边.

题目思路:

可以朴素的统计边。比较麻烦。这里给出一个比较巧妙的做法:

统计每四个相邻的格子中奇数个1的个数。

原理就是统计顶点个数(点个数=边个数).因为我们可以发现只有在 角的情况下,格子中才可能出现奇数个1.

10 00
11 01

F - GCD or MIN
题目大意:

给你一个数列。你每次可以拿两个数出来删掉,然后要么做 g c d gcd gcd要么做 m i n min min.得到结果再放入数列中。最后只会剩下一个数。问你这个数可能种数。

题目思路:

其实不难看出, m i n min min操作的结果就是删去一个数。且只有最小值不能被删去.且 g c d gcd gcd的操作也是单调递减的。所以最后这个数的大小一定小于等于 m i n { a i } min\{a_i\} min{ai}

所以问题可以转化为:让你从 n n n个数中选取出一个子集 g c d gcd gcd。问你有多少种结果 ≤ m i n { a i } \leq min\{a_i\} min{ai}.

注:因为我们一旦从一个子集中gcd出一个 ≤ m i n { a i } \leq min\{a_i\} min{ai}的数。接下来就是把他们全 m i n min min起来。这样就可以实现上述效果了。

如何求子集GCD的个数?

对于一个数 a i a_i ai,包含它的 g c d gcd gcd的最终结果一定是它的因子。

所以我们对每个数 a i a_i ai求解它的因数。对于每个因数 f i f_i fi,我们用map存下来有哪些 a i a_i ai中含有它(所以它们之间含有公共因子 f i f_i fi)。然后枚举因数,对对应的 a i a_i ai求一遍gcd,如果 = f i = f_i =fi,那么答案++.

时间复杂度:

O ( n m a x { a i } ) O(n\sqrt{max\{a_i\}}) O(nmax{ai} )

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2000 + 5;
const int mod = 1e9 + 7;
map<ll,vector<ll>> q;
int main()
{
    ios::sync_with_stdio(false);
    int n; cin >> n;
    ll d = 1e9;
    for (int i = 1 ; i <= n ; i++){
        ll x ; cin >> x;
        d = min(d , x);
        for (ll j = 1 ; j * j <= x ; j++){
            if (x % j == 0){
                q[j].push_back(x);
                if (j * j != x) q[x/j].push_back(x);
            }
        }
    }
    int ans = 0;
    for (auto g : q){
        if (g.first > d) break;
        ll gcd = g.second[0];
        for (auto k : g.second) gcd = __gcd(gcd , k);
        if (gcd == g.first) ans++;
    }
    cout << ans << endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值