CF1497D Genius
题意:
n个问题从i到n编号,第i个问题给出的ci=2i,tagi,sic_i=2^i,tag_i,s_ici=2i,tagi,si
解决问题i后解决问题j条件是:IQ<|ci−cjc_i-c_jci−cj|,同时获得|si−sjs_i-s_jsi−sj|分
问题解决得次数和顺序不受限制
一开始IQ=0,求最高可获得得分数
内存限制31.25MB,大致可以开1e7的数组
题解:
很明显动态规划,按照一般思路设dp[i][j]:上一次是第i个问题,本次是第j个问题的最大贡献。但是很明显空间不够
对于dp[][]的状态转移,当且仅当∣ck−cj∣>∣ci−cj∣|c_k-c_j|>|c_i-c_j|∣ck−cj∣>∣ci−cj∣,可以从dpi,jdp_{i,j}dpi,j转移到dpj,kdp_{j,k}dpj,k
我们将这个∣ci−cj∣|c_i-c_j|∣ci−cj∣放在图论上分析,就是有n个点,任意两点之间建边,边权为∣ci−cj∣|c_i-c_j|∣ci−cj∣的一个无向图,我们可以在无向图商从小边权向大边权转移,这样就可以不用二维来转移,降低空间复杂度
设dpidp_idpi表示最后一个问题是i的最大贡献,当我们走(i,j)这条边时,状态i可以由状态j更新,同理,状态j也可以由状态i更新,因为这是无向边。
有转移方程:
val=∣si,sj∣val=|s_i,s_j|val=∣si,sj∣
tmpi=dpitmp_i=dp_itmpi=dpi
tmpj=dpjtmp_j=dp_jtmpj=dpj
dpi=max(dpi,tmpj+val)dp_i=max(dp_i,tmp_j+val)dpi=max(dpi,tmpj+val)
dpj=max(dpj,tmpi+val)dp_j=max(dp_j,tmp_i+val)dpj=max(dpj,tmpi+val)
不过问题还没完全解决,现在我们还要考虑几个问题:
- 边权一样,优先级顺序?
- 如何按照边权从小到大枚举边
因为ci=2ic_i=2^ici=2i,边权都是∣2i−2j∣|2^i-2^j|∣2i−2j∣的形式,说明对于任意不同的(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
#elsestartTime= clock();freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#elseendTime= 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();
}