zoukankan      html  css  js  c++  java
  • H.Hamster's Sequence(2019武大校赛现场赛)(莫队or前缀和+离线处理)(吉比特杯第二届湖北省程序设计大赛) 解题报告 Apare_xzc

    H.Hamster’s Sequence(2019武大校赛现场赛)(莫队/前缀和+离线处理)(吉比特杯第二届湖北省程序设计大赛) 解题报告

    xzc 2019/4/18

    CCNU_你们好强啊我们都是面包手


    题意:
      给出n个整数a1,a2…an ,和m个询问,每次询问从[L,R]这个区间所有数的乘积的因数的个数 (求a[L]*a[L+1]*a[L+2]*…*a[R-1]*a[R] 的因数的个数)


    input:

    5 5
    1 2 3 4 5
    1 1
    2 2 
    3 3 
    1 5
    4 5
    

    output:

    1
    2
    2
    16
    6
    

    分析:
      一个数因数的个数是所有质因子出现的个数+1后的乘积
      剩下的上题解:

    • 首先,我们得看出来这道题是个简单题。
    • 至于那个合数mod,实际上是唬人的,你一些数乘起来对合数取模可以直接取
    • 然后我们根据题目描述我们知道,说ai在2147483647以内,但由ai=rand()*rand()得出,实际上ai的质因子最大的不会超过32767(rand()在c++中的随机数据范围在0到 32767)
    • 我们知道一个因数的个数和这个数的质因数的个数有关
    A=a1^n1*a2^n2*a3^n3…an^nn因数的个数等于
    (1+n1) * (1+n2) * (1+n3) * … * (1+nn)
    
    • 然后计算答案:
      planA: 直接莫队
      planB:对于32767中的质数分别统计对答案的贡献,用前缀和计算即可

    先上我的AC代码

    /*
    Author: CCNU XuZhichao
    state:  AC
    2019/4/17 22:40  1105 
    */
    #include <bits/stdc++.h>
    #define For(i,a,b) for(register int i=(a);i<=(b);++i)
    #define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
    #define Mst(a,b) memset(a,(b),sizeof(a))
    #define LL long long
    #define MP make_pair
    #define pb push_back
    using namespace std;
    const int maxn = 1e5+20;
    const int N = 32767;  //3512个素数
    const int mod = 35808247;
    int cntOfPrime,sushu[N],n,m;
    bool notPrime[N+20];
    int mp[N+20];
    void getPrime(int &cnt)
    {
    	cnt = 0;
    	For(i,2,N)
    	{
    		if(!notPrime[i]) mp[i] = cnt, sushu[cnt++] = i;
    		for(int j=0;j<cnt&&1ll*i*sushu[j]<=N;++j)
    		{
    			notPrime[i*sushu[j]] = true;
    			if(i%sushu[j]==0) break;
    		}
    	}
    }
    pair<int,int> ask[maxn]; 
    int a[maxn];
    LL ans[maxn];
    int sum[maxn];
    void f(int i)
    {
    	int p = sushu[i];
    	sum[0] = 0;
    	For(i,1,n)
    	{
    		int x = a[i];
    		int cnt = 0;
    		while(x%p==0) ++cnt,x/=p;
    		sum[i] = sum[i-1]+cnt;
    	}
    	For(i,1,m)
    	{
    		int nn = sum[ask[i].second]-sum[ask[i].first-1]+1;
    		ans[i] = ans[i]*nn%mod;	
    	}
    }
    int main()
    {
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
        getPrime(cntOfPrime);
        scanf("%d%d",&n,&m);
        For(i,1,n) scanf("%d",a+i), ans[i] = 1;
        For(i,1,m)
        {
        	scanf("%d%d",&ask[i].first,&ask[i].second);
    	}
        For(i,0,3511)
        {
        	f(i);
    	}
    	For(i,1,m)
    		printf("%lld
    ",ans[i]);
        
        return 0;
    }
    

    这是第一发用vector压缩存储了所有因数前缀和的代码

    跑了100多秒,输出都正确,100000(询问)*3512(个素数)*2*log2(100000)(两次二分)
    /*
    Author: CCNU XuZhichao
    state:  TLE 
    2019/4/17 22:09  1105 
    */
    #include <bits/stdc++.h>
    #define For(i,a,b) for(register int i=(a);i<=(b);++i)
    #define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
    #define Mst(a,b) memset(a,(b),sizeof(a))
    #define LL long long
    #define MP make_pair
    #define pb push_back
    using namespace std;
    const int maxn = 1e5+20;
    const int N = 32767;  //3512个素数
    const int mod = 35808247;
    int cntOfPrime,sushu[N];
    bool notPrime[N+20];
    int mp[N+20];
    void getPrime(int &cnt)
    {
    	cnt = 0;
    	For(i,2,N)
    	{
    		if(!notPrime[i]) mp[i] = cnt, sushu[cnt++] = i;
    		for(int j=0;j<cnt&&1ll*i*sushu[j]<=N;++j)
    		{
    			notPrime[i*sushu[j]] = true;
    			if(i%sushu[j]==0) break;
    		}
    	}
    }
    int a[maxn];
    vector<pair<int,int> > v[3512];
    void f(int id)
    {
    	int x = a[id],p,t;
    	for(int i=0;i<cntOfPrime&&sushu[i]<=x/sushu[i];++i)
    	{
    		p = sushu[i];
    		if(x%p) continue;
    		int cntt = 0;
    		while(x%p==0) ++cntt,x/=p;
    		t = mp[p]; //下标
    		int sz = v[t].size();
    		if(sz>1) cntt+=v[t][sz-1].second;
    		v[t].pb(MP(id,cntt));
    	}
    	if(x>1)
    	{
    		t = mp[x];
    		int cntt = 1;
    		int sz = v[t].size();
    		if(sz>1) cntt+=v[t][sz-1].second;
    		v[t].pb(MP(id,cntt));
    	}
    }
    int getNum(int L,int R,int i)
    {
    	int x1 = upper_bound(v[i].begin(),v[i].end(),MP(L,1000))-v[i].begin()-1;
    	int x2 = upper_bound(v[i].begin(),v[i].end(),MP(R,1000))-v[i].begin()-1;
    	return max(0,v[i][x2].second-v[i][x1].second) + 1;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        getPrime(cntOfPrime);
        For(i,0,3511) v[i].push_back(MP(-2,0));
        int n,m,L,R;
        scanf("%d%d",&n,&m);
        For(i,1,n)
        	scanf("%d",a+i);
        For(i,1,n)
        	f(i); 
        //预处理前缀和0ms 
        while(m--)
        {
        	scanf("%d%d",&L,&R);
        	LL ans = 1;
        	For(i,0,3511) //100000个询问*3000*log(100000); 
        	{
        		ans  = ans * getNum(L-1,R,i)%mod;
    		}
    		printf("%lld
    ",ans);
    	}
        return 0;
    }
    

    附:武大出题人写的标程(莫队算法)

    #include <bits/stdc++.h>
    using namespace std;
    const int M = 100100;
    const long long MOD = 35808247;
    //MOD=5981*5987
    int n,m;
    struct node
    {
    	int l,r,id;
    }q[M];
    long long ans[M];
    vector<int>b[M];
    int hash1[M],block[M];
    int num[M],prime[M],len,flag[M];
    void update(int x,int y)
    {
    	for(int i=0;i<b[x].size();i++)
    		num[hash1[b[x][i]]]+=y;
    }
    long long get_ans()
    {
    	long long cnt=1;
    	for(int i=1;i<=len;i++)
    		if(num[i]!=0)
    			cnt=cnt*(num[i]+1)%MOD;
    	return cnt; 
    }
    bool cmp(const node &x,const node &y)
    {
    	if(block[x.l]==block[y.l])
    		return x.r<y.r;
    	return x.l<y.l;
    }
    void deal()
    {
    	int l=1,r=0;
    	for(int i=1;i<=m;i++)
    	{
    		for(;r<q[i].r;r++)
    			update(r+1,1);
    		for(;r>q[i].r;r--)
    			update(r,-1);
    		for(;l<q[i].l;l++)
    			update(l,-1);
    		for(;l>q[i].l;l--)
    			update(l-1,1);
    		ans[q[i].id]=get_ans();
    	}
    }
    void print()
    {
    	for(int i=1;i<=m;i++)
    		printf("%I64d
    ",ans[i]);
    	printf("
    ");
    }
    int main()
    {
    	//freopen("in.txt","r",stdin);
    	//freopen("stdout.txt","w",stdout); 
    	for(int i=2;i<=40000;i++)
    		if(!flag[i])
    		{
    			prime[++len]=i;
    			for(int j=i*i;j<=40000;j+=i)
    				flag[j]=1;
    			hash1[i]=len;
    		}
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    	{
    		int x;
    		scanf("%d",&x);
    		for(int j=1;prime[j]*prime[j]<=x;j++)
    			while(x%prime[j]==0)
    			{
    				b[i].push_back(prime[j]);
    				x/=prime[j];
    			}
    		if(x!=1)
    			b[i].push_back(x);
    	}
    	int block_num=300;
    	for(int i=1;i<=n;i++)
    		block[i]=(i/block_num)+(i%block_num==0);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&q[i].l,&q[i].r);
    		q[i].id=i;
    	}
    	sort(q+1,q+1+n,cmp);
    	deal();
    	print();
    	return 0;
    } 
    
    

    2019/4/18 07:11
  • 相关阅读:
    第六次作业--结对编程第二次
    OneZero第四周第三次站立会议(2016.4.13)
    结对编程体会2
    OneZero第四周第二次站立会议(2016.4.12)
    关于“单元测试工具”
    OneZero第四周第一次站立会议(2016.4.11)
    OneZero第四周——预完成功能点统计
    OneZero第三周第五次站立会议(2016.4.8)
    OneZero第三周第四次站立会议(2016.4.7)
    OneZero第三周第三次站立会议(2016.4.6)
  • 原文地址:https://www.cnblogs.com/Apare-xzc/p/12243647.html
Copyright © 2011-2022 走看看