CF1497D Genius

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1497D Genius相关的知识,希望对你有一定的参考价值。

CF1497D Genius

题意:

n个问题从i到n编号,第i个问题给出的 c i = 2 i , t a g i , s i c_i=2^i,tag_i,s_i ci=2i,tagi,si
解决问题i后解决问题j条件是:IQ<| c i − c j c_i-c_j cicj|,同时获得| s i − s j s_i-s_j sisj|分
问题解决得次数和顺序不受限制
一开始IQ=0,求最高可获得得分数
内存限制31.25MB,大致可以开1e7的数组

题解:

很明显动态规划,按照一般思路设dp[i][j]:上一次是第i个问题,本次是第j个问题的最大贡献。但是很明显空间不够
对于dp[][]的状态转移,当且仅当 ∣ c k − c j ∣ > ∣ c i − c j ∣ |c_k-c_j|>|c_i-c_j| ckcj>cicj,可以从 d p i , j dp_{i,j} dpi,j转移到 d p j , k dp_{j,k} dpj,k
我们将这个 ∣ c i − c j ∣ |c_i-c_j| cicj放在图论上分析,就是有n个点,任意两点之间建边,边权为 ∣ c i − c j ∣ |c_i-c_j| cicj的一个无向图,我们可以在无向图商从小边权向大边权转移,这样就可以不用二维来转移,降低空间复杂度
d p i dp_i dpi表示最后一个问题是i的最大贡献,当我们走(i,j)这条边时,状态i可以由状态j更新,同理,状态j也可以由状态i更新,因为这是无向边。
有转移方程:
v a l = ∣ s i , s j ∣ val=|s_i,s_j| val=si,sj
t m p i = d p i tmp_i=dp_i tmpi=dpi
t m p j = d p j tmp_j=dp_j tmpj=dpj
d p i = m a x ( d p i , t m p j + v a l ) dp_i=max(dp_i,tmp_j+val) dpi=max(dpi,tmpj+val)
d p j = m a x ( d p j , t m p i + v a l ) dp_j=max(dp_j,tmp_i+val) dpj=max(dpj,tmpi+val)
不过问题还没完全解决,现在我们还要考虑几个问题:

  1. 边权一样,优先级顺序?
  2. 如何按照边权从小到大枚举边

因为 c i = 2 i c_i=2^i ci=2i,边权都是 ∣ 2 i − 2 j ∣ |2^i-2^j| 2i2j的形式,说明对于任意不同的(i,j),所对应的边也一定不同。也就是不会有边权一样的边
对于第二个问题,因为有空间的限制,我们不可以存下所有边然后排序。此时我们观察(i,j)权值的变化情况,假设i<j,权值二进制状态下区间[i,j-1]的位置都是1,说明当j越大时,权值越大,当j一样时,i越小权值越大
那么我们就看这样枚举点对(i,j),先枚举j,从小到大,然后枚举i,从大到小,这样枚举出来的边权保证从小到大

代码:

#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
    x= 0;
    char c= getchar();
    bool flag= 0;
    while (c < '0' || c > '9')
        flag|= (c == '-'), c= getchar();
    while (c >= '0' && c <= '9')
        x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
    if (flag)
        x= -x;
    read(Ar...);
}
template <typename T> inline void write(T x)
{
    if (x < 0) {
        x= ~(x - 1);
        putchar('-');
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
    startTime= clock();
    freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
    endTime= clock();
    printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn= 5e3 + 9;
ll tag[maxn];
ll s[maxn];
ll dp[maxn];
int x[maxn][maxn];
int main()
{
    //rd_test();
    int t;
    read(t);
    while (t--) {
        int n;
        cin >> n;
        memset(dp, 0, sizeof(dp));
        for (int i= 1; i <= n; i++)
            cin >> tag[i];
        for (int i= 1; i <= n; i++)
            cin >> s[i];
        for (int j= 2; j <= n; j++) {
            for (int i= j - 1; i >= 1; i--) {
                if (tag[i] == tag[j])
                    continue;
                ll tmpi= dp[i];
                ll tmpj= dp[j];
                ll val= abs(s[i] - s[j]);
                dp[i]= max(dp[i], tmpj + val);
                dp[j]= max(dp[j], tmpi + val);
            }
        }
        ll maxx= 0;
        for (int i= 1; i <= n; i++) {
            maxx= max(maxx, dp[i]);
        }
        cout << maxx << endl;
    }
    //Time_test();
}

以上是关于CF1497D Genius的主要内容,如果未能解决你的问题,请参考以下文章

CF1492D - Genius’s Gambit

CF1492D - Genius’s Gambit

如何从后台弹出片段

Google在与Genius的法律斗争中又取得胜利

genius-storage使用文档,一个浏览器缓存工具

POJ 2756 Autumn is a Genius 大数加减法