zoukankan      html  css  js  c++  java
  • 「余姚中学 2019 联测 Day 4」随机除法

    「余姚中学 2019 联测 Day 4」随机除法

    好题,难就难在转移的高位前缀和

    首先是一个浅显的( ext{dp})状态,令(n=Pi prime_i^{c_i})

    则状态只跟({c_i})有关,这是一个可重集合,强制定义(c_ige c_{i-1})最小表示出所有不同状态

    搜索一下( ext{dp})状态,发现只有(170000)左右的状态数

    直接枚举因数转移复杂度显然是升天的,直接枚举子集状态转移复杂度也很高,并且不好确定系数

    所以用一个高位前缀和处理优化枚举因数的转移

    再说一遍,是高位前缀和枚举因数的转移,不同的因数可能对应同一个状态

    常见的高位前缀和是(dp_{i,S}=dp_{i-1,S}+dp_{i,S-{S_i}})

    转移具有单调性,对于状态排序之后,定义辅助数组(dp_{i,j})表示对于(i)这个状态

    它的子集(注意这个子集是未排序的)中和它不同的最低位置(ge j)的总和

    计算高位前缀和时,每次转移只会对于一个位置改变

    枚举状态时,取得位置是(j),调用时需要排序

    而排完序之后(j)可能会后移,所以需要定义成(ge j)的,否则会算多

    比如转移((1,1,1)leftarrow (0,1,1),(1,0,1),(1,1,0))

    如果定义成(le j)的状态,三种状态转移之后都变成((1,1,0))

    原先在这个状态里的三个位置编号是((0,1,2))

    如果都去((1,1,0))这个状态里转移过来,原先((0,1,2))对应的下标位置改变,变成

    ((1,2,0))

    ((0,2,1))

    ((0,1,2))

    我们访问的时候访问的应该是子状态中不同位置(le j)的总和

    而从这个下标改变的状态里转移过来时,原先(>j)的下标被移移动进(le j)的范围

    再转移就错了

    所以正确定义状态之后就可以高位前缀和了

    存储和访问状态可以用( ext{Hash,Trie,int128})三种方法存储,( ext{int128})真香啊

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef __int128 Node;
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    #define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
    #define Mod1(x) ((x>=P)&&(x-=P))
    
    const int N=180000,P=1e9+7;
    
    ll qpow(ll x,ll k=P-2) {
    	ll res=1;
    	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
    	return res; 
    }
    Node Max,st[N];
    int m,a[100],cnt,dp[N][20],F[N],pri[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79};
    char str[30];
    
    int Find(Node s){ return lower_bound(st+1,st+cnt+1,s)-st; }
    void Load(Node s){
    	rep(i,1,20) a[i]=0;
    	for(int i=1;i<=20 && s>1; ++i) while(s%pri[i]==0) s=s/pri[i],a[i]++;
    }
    void dfs(int p,int lst,Node s) { 
    	st[++cnt]=s;
    	rep(i,1,lst) {
    		if((s*=pri[p])>Max) return;
    		dfs(p+1,i,s);
    	}
    }
    
    
    int main(){
    	freopen("div.in","r",stdin),freopen("div.out","w",stdout);
    	Max=1e12,Max=Max*Max;
    	dfs(1,100,1);
    	fprintf(stderr,"States Number = %d
    ",cnt);
    	sort(st+1,st+cnt+1);
    	rep(i,2,cnt) {
    		Node now; Load(now=st[i]);
    		int c=1;
    		rep(i,1,18) c=1ll*c*(a[i]+1)%P;
    		drep(j,18,0) {
    			if(!a[j]) dp[i][j]=dp[i][j+1];
    			else {
    				int k=j;
    				while(k>1 && a[k-1]==a[k]) --k;
    				int p=Find(now/pri[j]);
    				drep(d,j,k) {
    					dp[i][d]=dp[i][d+1]+dp[p][d];
    					Mod1(dp[i][d]);
    				}
    				j=k;
    			}
    		}
    		F[i]=(dp[i][1]+c)*qpow(c-1)%P;
    		rep(j,1,18) dp[i][j]+=F[i],Mod1(dp[i][j]);
    	}
    	while(~scanf("%s%d",str,&m)) {
    		Node n=0;
    		for(int i=0;str[i];++i) n=n*10+(str[i]-'0');
    		rep(i,1,m) {
    			int x;scanf("%d",&x); a[i]=0;
    			while(n%x==0) n=n/x,a[i]++;
    		}
    		sort(a+1,a+m+1,greater <int> ());
    		n=1;
    		rep(i,1,m) rep(j,1,a[i]) n=n*pri[i];
    		printf("%d
    ",F[Find(n)]);
    	}
    }
    
    
  • 相关阅读:
    Notes for GGX paper
    vsix dll缺失问题
    c# 引用其他工程问题
    Springboot+Maven
    http 带cookie值的Post请求(关联测试)
    http 带cookie值的get请求(关联测试)
    DefaultHttpClient 获取cookie信息
    HttpClient+ ResourceBundle接口配置优化
    Cookie和Session的区别
    moco框架——重定向
  • 原文地址:https://www.cnblogs.com/chasedeath/p/13064906.html
Copyright © 2011-2022 走看看