• [ABC200E] Patisserie ABC 2


    前言

    你说为什么一定要想 (O(nlog_2n)) 或者数学做法直接算呢?OI 血统的 ( t dp) 不香吗?

    题目

    AtCoder

    讲解

    我们如果知道了三种值的和,以及其对应的前缀方案数,那么就可以很轻松求出答案了。

    考虑 ( t dp)。这是一个类似于背包的过程,虽然跟背包好像差的有点远

    (dp_{i,j}) 表示 (i) 个数总和为 (j),每个数不超过 (n) 的方案数。其实知道了用 ( t dp) 以及状态之后,转移并不困难,具体可以参见代码。

    注意我们求的是前缀和形式。

    时间复杂度 (O(n))

    代码

    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); k = Read(); 
    	for(int i = 1;i <= n;++ i) dp[0][i] = i;//这个是前缀和
    	for(int i = 2;i <= 2*n;++ i) dp[1][i] = dp[0][Min(i-1ll,n)] - dp[0][Max(i-n-1,0ll)],dp[1][i] += dp[1][i-1];
    	for(int i = 3;i <= 3*n;++ i) dp[2][i] = dp[1][Min(i-1ll,2*n)] - dp[1][Max(i-n-1,0ll)],dp[2][i] += dp[2][i-1];
    	for(int S = 3;S <= 3*n;++ S)
    	{
    		if(dp[2][S] >= k)
    		{
    			k -= dp[2][S-1];
    			for(int i = 1;i <= n;++ i)
    				if(S-i >= 2 && S-i <= 2*n)
    				{
    					if(dp[1][S-i]-dp[1][S-i-1] >= k)
    					{
    						for(int j = 1;j <= n;++ j)
    							if(S-i-j >= 1 && S-i-j <= n)
    							{
    								if(dp[0][S-i-j]-dp[0][S-i-j-1] >= k)
    								{
    									Put(i,' '),Put(j,' '),Put(S-i-j);
    									return 0;
    								}
    								else k -= dp[0][S-i-j]-dp[0][S-i-j-1];
    							}
    					}
    					else k -= dp[1][S-i] - dp[1][S-i-1];
    				}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    [Flux] Component / Views
    [Flux] Stores
    [WebStrom] Change default cmd to Cygwin
    [AngularJS] ng-if vs ng-show
    [ES6] Array.find()
    [ES6] Array.findIndex()
    [Javascript] Object.assign()
    [Javascript] Intro to the Web Audio API
    [Falcor] Indroduce to Model
    [Farcol] Introduce
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14761781.html
Copyright © 2020-2023  润新知