• Codeforces Round #740 D2. Up the Strip


    题意:有n阶楼梯,假设当前你处于第x阶,那么走到第[1,x-1]阶或第(lfloor dfrac{x}{k} floor(2le k le x))​​​阶,问从n阶到1阶的方案数

    即求递归式

    [ m f(x)=sumlimits_{i=1}^{x-1}f(i)+sum_{i=2}^{x}f(lfloor dfrac{x}{i} floor) ]

    注意到前面(sum_{i=1}^{x-1}f(i))可以用前缀和O(1)计算,问题就是快速计算后面的式子

    首先想到了整除分块,就完成了一个( m O(nsqrt n))的算法,可以通过Easy Version的数据

    考虑如何更快地完成这个操作,正难则反,考虑每个f(x)往后的贡献

    对于一个f(x),它能贡献到的位置v,满足存在一个k,使得

    [lfloor dfrac{v}{k} floor=x ]

    化简就是

    [kxle v < k(x+1) ]

    就是说,枚举一个k,x能贡献到的是一个连续区间[kx,k(x+1))

    这样的枚举是倍数型的,用差分+前缀和完成区间加(因为只会往后加)

    复杂度有一个调和级数,为( m O(nlog n))

    /*
     * Author	: GhostCai
     * Expecto Patronum
    */
    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    
    void debug_out() { cerr << endl; }
    template <typename Head, typename... Tail>
    void debug_out(Head H, Tail... T){cerr << " " << H;debug_out(T...);}
    void shit(){puts("NO");}
    void good(){puts("YES");}
    #define debug(...) 
        cerr << __LINE__ << " [" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
    #define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
    #define pb push_back
    #define fi first
    #define se second
    #define read(a,n) for(int i=1;i<=n;i++) a[i]=rd()
    #define mem0(a) memset(a,0,sizeof(a))
    #define rep(x,y,z) for(int x=y;x<=z;x++)
    #define eep(i,x) for(int i=head[x];i;i=e[i].next)
    inline int rd(){
    	int ret=0,f=1;char c;
    	while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    	while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    	return ret*f;
    }
    #define pc putchar
    #define space() pc(' ')
    #define nextline() pc('
    ')
    void pot(int x){if(!x)return;pot(x/10);pc('0'+x%10);}
    void out(int x){if(!x)pc('0');if(x<0)pc('-'),x=-x;pot(x);}
    
    const int MAXN = 5000006;
    
    int n,MOD;
    
    int f[MAXN],g[MAXN];
    
    void solve(){
    	n=rd();MOD=rd();
    	f[1]=1;
    	rep(i,1,n){
    		(g[i]+=g[i-1])%=MOD;
    		(f[i]+=g[i])%=MOD;
    		(g[i+1]+=f[i])%=MOD;
    		(g[n+1]-=f[i])%=MOD;
    		for(int k=2;k*i<=n;k++){
    			int l=k*i,r=min(n+1,k*i+k);
    			g[l]=(g[l]+f[i])%MOD;
    			g[r]=(g[r]-f[i])%MOD;
    		}
    	}	
    	f[n]%=MOD;
    	if(f[n]<0) f[n]+=MOD;
    	cout<<f[n]<<endl;
    }
    
    signed main(){
    	solve();
    	return 0;
    }
    

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/15185490.html

  • 相关阅读:
    Leetcode 611.有效三角形的个数
    Leetcode 606.根据二叉树创建字符串
    Leetcode 605.种花问题
    潘潘_策略投资:期货存在跨期套利和跨品种套利的机会
    雷公资本:我的交易系统02 --- 可预知的趋势
    西子凌波47:回答问题 2016-10-28
    西子凌波43:说几句 2016-03-07
    西子凌波39:当下状态2 (2015-11-07 22:33:22)
    西子凌波36:放假了。说一些题外话。 2015-09-04
    西子凌波35:简单的走势,还有不明白的吗? 2015-08-21
  • 原文地址:https://www.cnblogs.com/ghostcai/p/15185490.html
Copyright © 2020-2023  润新知