• CF889E Mod Mod Mod


    一、题目

    点此看题

    二、解法

    真是第一次见,这是一道 (dp) 维护直线函数的题。

    (x_i=X \% a_1 \% a_2 ...\% a_i),如果 (x_i>0),那么 (X)(1)(x_1,x_2...x_i) 必定减 (1),考虑到 (i) 的答案是 (sum_{j=1}^i x_j),那么此种情况下答案就会减少 (i)这样我们找到了答案和 (X) 的关系:答案是 (icdot X+b) 的形式。

    那么考虑 (dp) 来维护函数,设 (dp[i][j]) 考虑到 (i),函数 (x_ileq j) 的最大 (b),转移考虑添加模数 (a_{i+1})

    • 如果 (j<a_{i+1}),那么这个模数对函数没有任何影响:(dp[i+1][j]leftarrow dp[i][j])

    • 否则 (jgeq a_{i+1}),考虑函数的上界会被模成 (a_{i+1}-1),那么以前的函数只有两段最优,我们只需要考虑它们的转移。

    (y=a_{i+1}-1+a_{i+1}lfloorfrac{j-a_{i+1}+1}{a_{i+1}} floor),也就是模 (a_{i+1}) 之后最大的数,这一段在原函数中是 ((y-a_{i+1},y]),取模之后相当于 (kin [0,a_{i+1})),那么取模之后函数的方程式:((i+1)cdot k+ia_{i+1}lfloorfrac{j-a_{i+1}+1}{a_{i+1}} floor+dp[i][j]),有转移:

    [dp[i+1][a_{i+1}-1]leftarrow dp[i][j]+ia_{i+1}lfloorfrac{j-a_{i+1}+1}{a_{i+1}} floor ]

    还有一段是 ((y,j]),取模之后相当于 (kin[0,j\%a_{i+1}]),考虑 (j) 处原来的点值是 (ij+dp[i][j]),新的点值是 (ij+j\% a_{i+1}+dp[i][j]),函数斜率是 (i+1),写出方程式:((i+1)cdot k+i(j-j\% a_{i+1})+dp[i][j]),有转移:

    [dp[i+1][j\% a_{i+1}]leftarrow dp[i][j]+i(j-j\% a_{i+1}) ]

    现在来分析一波时间复杂度,有一个 (a_{i+1}-1) 位置的插入,每次转移都会使之减少 (frac{1}{2}),所以每个初始的位点会转移 (O(log a)) 次,用 ( t map) 维护 (dp) 数组,那么时间复杂度 (O(nlog nlog a))

    三、总结

    总结一下 (dp) 维护直线函数的注意事项,毕竟这是一个船新题型。

    首先观察题目给的权值,如果是相加之类的一次操作但值域很大可以往这个方面考虑。

    然后就是找函数关系式,看权值是否和某个量存在直线关系。

    操作函数时(转移)考虑维护最大的 (b),那么取最优段转移即可,排除一定不优的转移。

    #include <cstdio>
    #include <map>
    using namespace std;
    #define int long long
    #define mit map<int,int>::iterator
    const int M = 200005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,ans,a[M];map<int,int> mp;
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	mp[a[1]-1]=0;
    	for(int i=2;i<=n;i++)
    		for(mit it=mp.lower_bound(a[i]);it!=mp.end();mp.erase(it++))
    		{
    			int x=it->first,y=it->second;
    			mp[x%a[i]]=max(mp[x%a[i]],y+(i-1)*(x-x%a[i]));
    			mp[a[i]-1]=max(mp[a[i]-1],y+(i-1)*((x+1)/a[i]*a[i]-a[i]));
    		}
    	for(mit it=mp.begin();it!=mp.end();it++)
    		ans=max(ans,it->second+n*it->first);
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    javascript ext 闭包
    Hibernate HQL from superclass 问题
    sql查询按in顺序排序显示数据 oracle
    Hibernate createSQLquery()
    sql 分页
    javasript 闭包测试
    Excel 批量快速导入mySQL 解决方案~~
    C# 注册COM+组件步骤~
    QT错误集锦~
    QuartzNet Test~~
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15082636.html
Copyright © 2020-2023  润新知