zoukankan      html  css  js  c++  java
  • [YY题]HDOJ5288 OO’s Sequence

    题意:求这个式子 $sum limits_{i=1}^{n} sum limits_{j=1}^{m} f(i, j) mod (10^9 + 7)$ 的值

    就是对每个区间[i, j]枚举区间中的每个数$a_i$到$a_j$, 判断这个$a$是否对[i, j]这个区间内所有数取模都不等于0, 若是,则这个区间满足条件

    问有多少个满足条件的区间

    比如案例是这样跑的

        int ans=0;
        for(int i=1;i<=5;i++)
            for(int j=i;j<=5;j++)
            {
                for(int k=i;k<=j;k++)   // 注意要枚举[i, j]中的每个数
                {
                    bool flag=0;
                    for(int l=i;l<=j;l++)
                        if(k!=l && k%l==0)
                            flag=1;
                    if(!flag)           // 对区间内所有数取模都不等于0 
                        ans++;
                }
            }

    跟省赛某题很像, 计算每个数a[i]对ans的贡献

    比如对于案例 1 2 3 4 5

    1这个数字对于答案的贡献是{1}, {1, 2}, {1, 2, 3}, {1, 2, 3, 4}, {1, 2, 3, 4, 5} 这5个区间

    2 这个数字对于答案的贡献是{2}, {2, 3}, {2, 3, 4}, {2, 3, 4, 5} 这4个区间   ( {1, 2}区间不满足,因为2%1==0 )

    ... ...

    来看4 这个数 

    它往左取区间 {4}, {3, 4} 当取到2的时候, 发现4%2==0了,那么就不必再往左了(对于连续的区间, 再往左则必定会经过2,那么该区间就不合法了)

    同理,可以想到往右取, 当找到一个数被它取模等于0, 那么就不必再往右了

    好了,现在对于一个数a[i], 它左边 到 不合法的数(被它取模等于0)为止 之间有x个数, 右边到不合法的数为止 有y个数

    那么a[i]这个数对答案的贡献就是(x+1)*(y+1)

    为什么呢?

    因为是连续的区间, 所以这个区间的左端点可以取a[i]左边0个数、1个数、2个数... ...x个数;右边0个数、1个数、2个数... ...y个数

    左边有(x+1)种取法,右边有(y+1)种, 相乘就是总取法数

    那么我们只要找到离a[i]最近的一左一右两个不合法数的位置$l$和$r$, 那么$(i-l)*(r-i)$ 就是a[i]的贡献($i-l-1$就是上面所讲的x)

    之后只要遍历每个a, 将每个a的贡献累加起来即是最后答案。

    那么现在问题就转化成了如何求一个 离它最近的 能被它整除的数 的位置

    我们是这样做的:

    开个数组将每个a[i]的倍数都记为i  (比如 a[0]=2, 那么就将2、4、6... ...10000 都记下0号位置;a[x]=y, 就将y、2y、3y... ... 都记下x位置)

    就跟筛因子一样   (因为1比较特殊,会退化到$n^2$, 因此特殊处理)   复杂度为O(NlogN)  (N为10000, 因为数最大为10000)

            for(int i=0;i<n;i++)
            {
                if(a[i]==1)
                    one.push_back(i);
                else
                    for(int j=a[i];j<=10000;j+=a[i])
                        b[j].push_back(i);
            }  

    因为是按顺序遍历了a数组, 所以记下的位置(比如2 2 3 6 12  对于12记下的是0 1 2 3 4 )一定是递增的

    那么就可以二分来寻找离$i$最近的位置

    p.s. lower_bound 找的是大于等于x的数位置

          upper_bound找的是大于x的数的位置

     1 const LL mod=1e9+7;
     2 int a[100005];
     3 vector<int> b[10005];
     4 vector<int> one;
     5 int read()
     6 {
     7     char ch=' ';
     8     int ans=0;
     9     while(ch<'0' || ch>'9')
    10         ch=getchar();
    11     while(ch<='9' && ch>='0')
    12     {
    13         ans=ans*10+ch-'0';
    14         ch=getchar();
    15     }
    16     return ans;
    17 }
    18 
    19 int main()
    20 {
    21 //    freopen("1001.in", "r", stdin);
    22 //    freopen("out.txt", "w", stdout);
    23     int n;
    24     while(~scanf("%d", &n))
    25     {
    26         for(int i=0;i<n;i++)a[i]=read();
    27 //            scanf("%d", &a[i]);
    28         for(int i=0;i<=10000;i++)
    29         {
    30             b[i].clear();
    31             b[i].push_back(-1);
    32         }
    33         one.clear();
    34         one.push_back(-1);
    35         for(int i=0;i<n;i++)
    36         {
    37             if(a[i]==1)
    38                 one.push_back(i);
    39             else
    40                 for(int j=a[i];j<=10000;j+=a[i])
    41                     b[j].push_back(i);
    42         }
    43         for(int i=0;i<=10000;i++)
    44             b[i].push_back(n);
    45         one.push_back(n);
    46         LL ans=0;
    47         for(int i=0;i<n;i++)
    48         {
    49             int p1=lower_bound(b[a[i]].begin(), b[a[i]].end(), i)-b[a[i]].begin()-1;
    50             int p2=lower_bound(one.begin(), one.end(), i)-one.begin()-1;
    51             int l=max(b[a[i]][p1], one[p2]);
    52             p1=upper_bound(b[a[i]].begin(), b[a[i]].end(), i)-b[a[i]].begin();
    53             p2=upper_bound(one.begin(), one.end(), i)-one.begin();
    54             int r=min(b[a[i]][p1], one[p2]);
    55 //            printf("%d %d
    ", l, r);
    56             ans=(ans+((i-l)*(r-i))%mod)%mod;
    57         }
    58         printf("%I64d
    ", ans%mod);
    59     }
    60     return 0;
    61 }
    HDOJ 5288
  • 相关阅读:
    centos8 将SSSD配置为使用LDAP并要求TLS身份验证
    Centos8 搭建 kafka2.8 .net5 简单使用kafka
    .net core 3.1 ActionFilter 拦截器 偶然 OnActionExecuting 中HttpContext.Session.Id 为空字符串 的问题
    Springboot根据不同环境加载对应的配置
    VMware Workstation12 安装 Centos8.3
    .net core json配置文件小结
    springboot mybatisplus createtime和updatetime自动填充
    .net core autofac依赖注入简洁版
    .Net Core 使用 redis 存储 session
    .Net Core 接入 RocketMQ
  • 原文地址:https://www.cnblogs.com/Empress/p/4665979.html
Copyright © 2011-2022 走看看