51nod 矩阵无重复元素 V2

来源:互联网 发布:淘宝天下是阿里的吗 编辑:程序博客网 时间:2024/04/29 15:51

传送门:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1026
题解:
其实我并不知道正解是什么,搜索了一晚上没有找到用容斥原理做这道题的方法,思考没有得到结果,可能因为我是正常人吧。
考虑集合分类计数,考虑,将所有的底数a分解质因数,质因数的指数为ai,取 k=gcd(a1,a2an),将每个ai除以k,这样得到的指数是互质的,化简完成后得到的序列连同质数相同的作为一个集合计数,考虑发现,假设集合标志为xx为集合最小底数),那么相同集合的形式是xk,我们把它们放在一起计数,考虑矩阵中一定是一段连续的
x1 x2 xk,而且个数为Ologn,这时只需要考虑指数有多少种不同的值就好了,我们暴力求解,开一个bool数组,这一步是O(nlog2n)的,然后就把a扫一遍统计答案了,这一步复杂度是O(nlogn),其实如果手算看起来很大,但其实第一个常数很小,第二个上界很松,是可以卡过的。

代码:

#include<iostream>#include<cstring>#include<string>#include<cstdio>#define N 1000000#define S 18using namespace std;typedef long long LL; LL ans,m,n,a,b,num,sum,t[N + 5],f[N + 5],g[S + 5][S + 5],l[N + 5],r[N + 5];bool vis[N * S + 5],flag[N + 5];inline void get_g(){    for (int i = 1;i <= S; ++i){        sum = 0;        memset(vis,0,sizeof(vis));      for (int j = i;j <= S; ++j){           for (int p = b;p < b + m; ++p)             if (!vis[p * j]) { ++sum; vis[p * j] = 1;}         g[i][j] = sum;      }   }}inline void init(){    scanf("%lld%lld%lld%lld",&m,&n,&a,&b);    memset(f,0,sizeof(f));    memset(flag,0,sizeof(flag));    for (LL i = 2;i <= N; ++i)        if (!flag[i]){          num = 1;          for (LL j = i;j <= N;j *= i){                if (j != i) flag[j] = 1;                 f[j] = num;                 t[j] = i;                ++num;          }    }    get_g();    for (int i = a;i < n + a;++i)      if (!l[t[i]]) l[t[i]] = f[i];    for (int i = n + a - 1;i >= a;--i)      if (!r[t[i]]) r[t[i]] = f[i];    ans = 0;    for (int i = 1;i < n + a; ++i)      if (!flag[i]) ans = (ans + g[l[i]][r[i]]); }int main(){    init();    cout<<ans;    return 0;}

注意:1.循环变量优势会爆int
2.bool的内存是int 的1/4,不要算错了

0 0
原创粉丝点击