题目链接
3 1 3 3 10 3 4 2 4 4 2 4 3 2 2
2 7
题意:给N个数,a1,a2....an,表示目标状态,初始状态为空,每次操作可以将一段连续的区间变成目标状态,花费为这段区间出现的不同的数字数的平方。求最后变到目标状态的最小花费。
题解:容易想到n^2的dp,用dp[ i ]表示把前i个数变成目标状态的最小花费,转移就是
dp[ i ]=min(dp[ i ],dp[ j ] +huafei (j+1,i)),0<=j<i 。而n^2的复杂度显然太高。因为花费为出现的不同的数字的个数的平方,所以每次操作最多包含sqrt(n)个数字。对于dp[i],我们 处理出每个数字小于i且离i最近的位置,最多转移sqrt(i)个数字。而处理每个数字小于i且离i最近的位置,可以用set或者链表维护一下。复杂度n*sqrt(n),当然要先将数字离散化。(由于这题时限卡得很紧,所以我进行了缩点优化)。
用链表维护的代码如下:
#include<stdio.h> #include<algorithm> #include<queue> #include<stack> #include<map> #include<set> #include<vector> #include<iostream> #include<string.h> #include<string> #include<math.h> #include<stdlib.h> #define inff 0x3fffffff #define eps 1e-8 #define nn 51000 #define mod 1000000007 typedef long long LL; using namespace std; int n; int a[nn]; struct node { int val,id; }b[nn]; bool cmp(node x,node y) { return x.val<y.val; } int c[nn]; int dp[nn]; int wei[nn]; struct lian { int val,next,pre; }d[nn]; int head,num; void add(int val) { d[num].val=val; d[num].next=head; d[num].pre=-1; wei[val]=num; if(head!=-1) { d[head].pre=num; } head=num++; } void erase(int val) { int ix=d[wei[val]].pre; if(ix!=-1) d[ix].next=d[wei[val]].next; ix=d[wei[val]].next; if(ix!=-1) d[ix].pre=d[wei[val]].pre; } int W[nn]; int main() { int i,N,j; while(scanf("%d",&n)!=EOF) { a[0]=-1; N=0; for(i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]!=a[i-1]) { b[++N].val=a[i]; b[N].id=N; } } sort(b+1,b+N+1,cmp); int cnt=1; c[b[1].id]=1; for(i=2;i<=N;i++) { if(b[i].val!=b[i-1].val) { ++cnt; } c[b[i].id]=cnt; } for(i=0;i<=cnt;i++) { W[i]=-1; wei[i]=-1; } dp[0]=0; head=-1; num=0; add(0); int ix,fc; int fuck; for(i=1;i<=N;i++) { if(W[c[i]]!=-1) { erase(W[c[i]]); } W[c[i]]=i; add(i); dp[i]=i; fc=0; fuck=sqrt((double)i)+5; for(j=head;j!=-1;j=d[j].next) { ix=d[j].val; dp[i]=min(dp[i],dp[ix]+fc*fc); fc++; if(fc==fuck) break; } } printf("%d\n",dp[N]); } return 0; }
#include<stdio.h> #include<algorithm> #include<queue> #include<stack> #include<map> #include<set> #include<vector> #include<iostream> #include<string.h> #include<string> #include<math.h> #include<stdlib.h> #define inff 0x3fffffff #define eps 1e-8 #define nn 51000 #define mod 10000007 typedef __int64 LL; using namespace std; const LL inf64=(LL)inff*inff; int n; int a[nn]; int b[nn]; set<int>se; set<int>::iterator it; int dp[nn]; int wei[nn]; struct node { int val,id; }c[nn]; bool cmp(node x,node y) { return x.val<y.val; } inline int read() { char ch; bool flag=false; int re=0; while(!(((ch=getchar())>='0'&&(ch<='9'))||(ch=='-'))); if(ch!='-') { re*=10; re+=ch-'0'; } else flag=true; while((ch=getchar())>='0'&&(ch<='9')) { re*=10; re+=ch-'0'; } if(flag) re=-re; return re; } int main() { int i,fuck; while(scanf("%d",&n)!=EOF) { se.clear(); se.insert(0); int cnt=0; for(i=1;i<=n;i++) { a[i]=read(); } int N=0; a[0]=-1; for(i=1;i<=n;i++) { if(a[i]!=a[i-1]) { ++N; c[N].val=a[i]; c[N].id=N; } } sort(c+1,c+N+1,cmp); cnt=1; b[c[1].id]=1; for(i=2;i<=N;i++) { if(c[i].val==c[i-1].val) { b[c[i].id]=cnt; } else { b[c[i].id]=++cnt; } } for(i=1;i<=N;i++) { dp[i]=inff; } for(i=1;i<=cnt;i++) { wei[i]=-1; } dp[0]=0; int ix,wy; int fc; int jian=sqrt((double)n)+5; for(i=1;i<=N;i++) { ix=b[i]; fuck=sqrt((double)i)+5; if(wei[ix]==-1) { se.insert(i); } else { se.erase(wei[ix]); se.insert(i); } if((int)se.size()>jian) { it=se.begin(); se.erase(*it); } wei[ix]=i; it=se.end(); it--; fc=0; while(1) { wy=*it; dp[i]=min(dp[i],dp[wy]+fc*fc); fc++; if(fc==fuck) break; if(it==se.begin()) break; it--; } } printf("%d\n",dp[N]); } return 0; }