zoukankan      html  css  js  c++  java
  • 【CF889E】Mod Mod Mod DP

    【CF889E】Mod Mod Mod

    题意:给你一个序列$a_1,a_2...a_n$,定义$f(x,n)=xmod a_n$,$f(x,i)=xmod a_i+f(x mod a_i,i+1) (1 le i<n)$。

    最大化f(x,1)。

    $nle 200000,a_ile 10^9$

    题解:超级神的DP题。(题目名字好暴力啊~)

    首先有一个性质,一个数对一个比它小的数取模,最多取log次就会变成0。我们思考如何利用这个性质。

    如果我们令f[x][i]就是题目中的f(x,i),那么每次i++的时候我们都要更新所有的dp值。不过我们可以将答案变成i*x+b的形式,那么f[d][i]就代表当x<=d时,最大的b值。这也就是说,我们dp维护的其实使若干条线段,我们要在斜率一定的时候,最大化截距。

    思考如何转移,我们从f[d][i]可以转移到$f[d mod a_i][i+1]$,也可以转移到$f[a_i-1][i+1]$(前提:ai<=d)。我们发现我们可以将所有$f[a_i-1][i+1]$合并,并且对于d<ai的状态,dp值并不改变,我们可以不理会这些状态。所以时间复杂度是多少呢?

    上面已经说过了,一个数我们只在它被取模的时候更新状态,并且每次我们只新加入一个数ai-1,所以最终复杂度是$O(nlog n)$的。

    当然,如果你像我一样比较懒用map维护dp值,需要再加一个log。

    #include <cstdio>
    #include <cstring>
    #include <map>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    const int maxn=200010;
    typedef long long ll;
    ll n,ans,v;
    map<ll,ll> f;
    map<ll,ll>::iterator it;
    inline ll rd()
    {
    	ll ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd();
    	ll i,a,b;
    	f[rd()-1]=0;
    	for(i=2;i<=n;i++)
    	{
    		v=rd();
    		while(f.begin()!=f.end())
    		{
    			it=f.end(),it--,a=(*it).first,b=(*it).second;
    			if(a<v)	break;
    			f[v-1]=max(f[v-1],b+(i-1)*(a-a%v-v));
    			f[a%v]=max(f[a%v],b+(i-1)*(a-a%v));
    			f.erase(it);
    		}
    	}
    	for(it=f.begin();it!=f.end();it++)	ans=max(ans,n*((*it).first)+(*it).second);
    	printf("%I64d",ans);
    	return 0;
    }
  • 相关阅读:
    XML解析技术研究(一)
    Qt解析XML文件(QXmlStreamReader)
    Qt XML读取写入操作
    QT QXmlStreamWriter用法小结
    QtXML 举例
    libpcap使用
    PCAP研究
    粗谈pcap_next_ex()
    C#扇形的绘制与Hittest交互、图种制作
    ORA-01747: user.table.column, table.column 或列说明无效
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8052795.html
Copyright © 2011-2022 走看看