Codeforces Round 371 C Sonya and Problem Wihtout a Legend
2016-09-20 13:26
411 查看
Task:
给你一个长度为n的序列,每次操作能使序列中的数+1或-1,求最少的操作数,使得序列严格递增.
Sample Input
5
5 4 3 2 1
Sample Output
12
Hint
1<=n<=3000
Solution:
首先我们先明白一件事:我们有A[i]<A[i+1],也就可以转化为A[i]−i<=A[i]−i−1,那么我们在一开始将序列中的数减去i,题目就变成了将n个数通过最少的操作数变成一个递增的序列,这个可以通过O(n2)的dp做到.
定义dp[i][j]为前i个点,最后一个数为j的最小操作数.
就可以很简单地写出dp方程了:
dp[i][j]=min(dp[i−1][k]+|j−k|)
那么:
这道题还有一种神奇的写法:
如果有一个数a,b(a< b),那么我们可以用(b-a)的代价来把他们同时变成[a,b]的任意一个数.然后如果再来一个大于a的数c,我们只需把a,b都变成比c小就好了,而如果c比a小,把c变成a就好了(这时费用加上这个差),后来如果又来了一个数,还是比a小(但是比c大),我们只需把刚才那个费用用来将a,b变小就行了.
总的来说,如果现在堆中的最大值比我现在的值大,我就把答案加上它们的差,表示将小的变成大的(也有可能在后来它们会一起变小),否则我们就把它放到堆里,留给以后的数字将它变小.
那么用一个堆来维护数字,然后遇见堆中的最大值比现在的值大的时候,我们就把答案加上堆中最大值减去当前的数,再把堆中最大的数删去,加进当前的这个数.
最后输出答案就好了.
给你一个长度为n的序列,每次操作能使序列中的数+1或-1,求最少的操作数,使得序列严格递增.
Sample Input
5
5 4 3 2 1
Sample Output
12
Hint
1<=n<=3000
Solution:
首先我们先明白一件事:我们有A[i]<A[i+1],也就可以转化为A[i]−i<=A[i]−i−1,那么我们在一开始将序列中的数减去i,题目就变成了将n个数通过最少的操作数变成一个递增的序列,这个可以通过O(n2)的dp做到.
定义dp[i][j]为前i个点,最后一个数为j的最小操作数.
就可以很简单地写出dp方程了:
dp[i][j]=min(dp[i−1][k]+|j−k|)
那么:
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define M 3005 #define LL long long using namespace std; int pl[M],a[M]; LL dp[M][M]; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i]-=i; pl[i-1]=a[i]; } sort(pl,pl+n); int sz=unique(pl,pl+n)-pl; for(int i=1;i<=n;i++)a[i]=lower_bound(pl,pl+sz,a[i])-pl; for(int i=0;i<sz;i++)dp[1][i]=abs(pl[a[1]]-pl[i]); for(int i=2;i<=n;i++){ LL Mi=dp[i-1][0]; for(int j=0;j<sz;j++){ if(Mi>dp[i-1][j])Mi=dp[i-1][j]; dp[i][j]=Mi+abs(pl[a[i]]-pl[j]); } } LL ans=-1; for(int i=0;i<sz;i++) if(ans==-1||ans>dp [i])ans=dp [i]; cout<<ans<<endl; return 0; }
这道题还有一种神奇的写法:
如果有一个数a,b(a< b),那么我们可以用(b-a)的代价来把他们同时变成[a,b]的任意一个数.然后如果再来一个大于a的数c,我们只需把a,b都变成比c小就好了,而如果c比a小,把c变成a就好了(这时费用加上这个差),后来如果又来了一个数,还是比a小(但是比c大),我们只需把刚才那个费用用来将a,b变小就行了.
总的来说,如果现在堆中的最大值比我现在的值大,我就把答案加上它们的差,表示将小的变成大的(也有可能在后来它们会一起变小),否则我们就把它放到堆里,留给以后的数字将它变小.
那么用一个堆来维护数字,然后遇见堆中的最大值比现在的值大的时候,我们就把答案加上堆中最大值减去当前的数,再把堆中最大的数删去,加进当前的这个数.
最后输出答案就好了.
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> using namespace std; priority_queue<int>q; int main(){ long long ans=0; int n; scanf("%d",&n); for(int i=1;i<=n;i++){ int x; scanf("%d",&x); x-=i; q.push(x); if(q.top()>x){ ans+=q.top()-x; q.pop(); q.push(x); } } cout<<ans<<endl; return 0; }
相关文章推荐
- Codeforces 713C C. Sonya and Problem Wihtout a Legend (经典DP)
- [堆与斜率] Codeforces 713C - Sonya and Problem Wihtout a Legend
- Codeforces Round #371 (Div. 2) E. Sonya and Problem Wihtout a Legend(技巧 + 离散化dp)
- Codeforces Round #371 C. Sonya and Problem Wihtout a Legend (DP)
- Codeforces Round #371 (Div. 2)E. Sonya and Problem Wihtout a Legend[DP 离散化 LIS相关]
- 【CodeForces】713 C. Sonya and Problem Wihtout a Legend
- Codeforces Round #371 (Div. 1) C. Sonya and Problem Wihtout a Legend 贪心
- Codeforces Round #371 (Div. 2) C. Sonya and Queries (map)
- cf 714 e Sonya and Problem Wihtout a Legend
- Codeforces Round #371 (Div. 1) C. Sonya and Problem Wihtout a Legend
- Codeforces-713C-Sonya and Problem Wihtout a Legend
- codeforces 713C C. Sonya and Problem Wihtout a Legend(dp)(将一个数组变成严格单增数组的最少步骤)
- 动态规划,离散化(Sonya and Problem Wihtout a Legend,cf 713C)
- Codeforces Round #371 (Div. 2) E. Sonya and Problem Wihtout a Legend (DP/LIS变形)
- Codeforces 713 C Sonya and Problem Wihtout a Legend
- 【CF 713C】Sonya and Problem Wihtout a Legend(离散化+dp)<POJ 3666变形>
- 【CF713C】Sonya and Problem Wihtout a Legend(离散化,DP)
- cf/Codeforces Round #371 714E - Sonya and Problem Wihtout a Legend - dp +lis
- cf 372 div2 E. Sonya and Problem Wihtout a Legend dp
- Codeforces Round #371 (Div. 1) C. Sonya and Problem Wihtout a Legend(贪心+DP)