• hdu 5228 OO’s Sequence(单独取数算贡献)


    Problem Description
    OO has got a array A of size n ,defined a function f(l,r) represent the number of i (l<=i<=r) , that there's no j(l<=j<=r,j<>i) satisfy ai mod aj=0,now OO want to know
     
     
    Input
    There are multiple test cases. Please process till EOF.
    In each test case: 
    First line: an integer n(n<=10^5) indicating the size of array
    Second line:contain n numbers ai(0<ai<=10000)
     
    Output
    For each tests: ouput a line contain a number ans.
     
    Sample Input
    
    
    5
    1 2 3 4 5
     
    Sample Output
    
    
    23
     
    题意:给你n个数,让你找出各个区间内不被任何a[j]整除的i的个数,并输出所有区间的个数和。
    举个栗子,样例数据就是
    f(1,1)f(1,2)f(1,3)f(1,4)f(1,5)
    f(2,2)f(2,3)f(2,4)f(2,5)
    f(3,3)f(3,4)f(3,5)
    f(4,4)f(4,5)
    f(5,5)
    这些区间内的不被任何a[j]整除的个数
    因为题目a[i]%a[j]==0,i!=j,
    所以f(1,1) 里面有一个 1,因为i!=j;
    f(1,2) 里面有一个1,因为2%1==0
    以此类推 f(1,3) f(1,4) f(1,5) 都是 1
    f(2,2) 一个
    f(2,3) 两个 2 和 3 因为有两个数i可以不等于j
    以此类推相信题意已经懂了
    当初我就是被题意杀了,还狂做三小时,一丝悲凉>_<
     
    思路:既然他给的是求每个数不被其他的数整除的区间个数,说明这个区间里面肯定包含a[i]
    然后我们把每个数所包含的区间全部弄出来,当然要符合条件没有可以整除a[i]的数的区间,就是大佬们讲的求每个数的贡献,看他贡献几个区间,包含这个数的区间他能贡献出来几个
    重点!!我们找a[i]左边的最近的可以整除a[i]的数的位置,再找右边的
    举个栗子,比如 1 3 4 2 3 1
    我们当前在枚举中间那个2
    左边我们找到了位置1的1,右边找到了位置6的1
    现在一个公式 (i-left)*(right-i) 就是该区间内所有区间种数,并且没有可以整除a[j]的数
    意思就是1 3 4 2 3 1  因为两边都是最近的可以整出的,所以中间肯定都是满足要求的,然后这个公式懂了意思自己也能推出来,不过特别要注意 2 2这个区间,所以公式里面两边都包含了中间这个2
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<string>
    #include<queue>
    #include<vector>
    #include<map>
    #define MOD 1000000007
    using namespace std;
    int a[100001];
    int l[100001];//记录每个数的左边最接近得可整除的数的位置
    int r[100001];//记录每个数的右边最接近得可整除的数的位置
    int mp[100001];//记录之前出现过的数,判断是否是整除的数的标记数组,存的是那个数的位置
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {    
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
            }
            memset(mp,0,sizeof(mp));
            for(int i=1;i<=n;i++)//找左边最接近的数
            {
                l[i]=0;
                for(int j=1;j*j<=a[i];j++)//判断这个数是否被整除,取到根号就好
                {
                    if(a[i]%j==0)
                    {
                        if(mp[j]) l[i]=max(mp[j],l[i]);
                        if(mp[a[i]/j]) l[i]=max(mp[a[i]/j],l[i]);//这个是以根号为界限的右边的因子数,自己推导一下
                    }
                }
                mp[a[i]]=i;//出现过的数记录一下
            }
            memset(mp,0,sizeof(mp));
            for(int i=n;i>=1;i--)找右边最接近的数
            {
                r[i]=n+1;
                for(int j=1;j*j<=a[i];j++)
                {
                    if(a[i]%j==0)
                    {
                        if(mp[j]) r[i]=min(mp[j],r[i]);
                        if(mp[a[i]/j]) r[i]=min(mp[a[i]/j],r[i]);
                    }
                }
                mp[a[i]]=i;        
            }
            long long sum=0;
            for(int i=1;i<=n;i++)
            {
                sum+=(i-l[i])*(r[i]-i);//公式算每个数的贡献区间个数多少
            }
            printf("%lld
    ",sum%MOD);
        }
    }

    我个人觉得比赛的时候要有能力分清这个是否是一个求贡献的题目,下面讲下个人理解,我觉得如果一件事必须要这个成员参与

    ,而且有很多这类的的事,并且题目是要求每个个数之和之类的就是求贡献题

    也是个人一些推断,希望对你们有用,

    下面最后说一句,搞acm的小菜鸡绝不服输>_<`

  • 相关阅读:
    BZOJ 2120 数颜色
    BZOJ 3289 Mato的文件管理
    BZOJ 2038 小Z的袜子
    BZOJ 1878 HH的项链
    洛谷P2709 小B的询问
    6491: Daydream
    问题 L: An Invisible Hand
    HDU-2177 取(2堆)石子游戏 (威佐夫博奕)
    (POJ-3279)Fliptile (dfs经典---也可以枚举)
    问题 J: Palindromic Password ( 2018组队训练赛第十五场) (简单模拟)
  • 原文地址:https://www.cnblogs.com/Lis-/p/9311520.html
Copyright © 2020-2023  润新知