标签:
题意:一个数列,每个点代表一种颜色,每次选一个区间覆盖,覆盖的代价是区间内颜色种类数的平方,直到覆盖整个数列,求最小花费 思路:1、首先将相邻的两个相同的数合并,记录下它的idd号和数值 2、然后要将的值离散化,因为后面要用到标记数组vis,而a[i]的范围太大(10e9),所以要离散化后才能标记 3、定义一个dp[]数组,dp[i]表示取到i个数时的最小代价,注意dp[tot]=tot,因为最多也就tot,(可以一个一个取)。 4、这边有个剪枝(至关重要,不剪枝会超时),即if(dp[i]+tmp*tmp>=dp[tot]) break; 5、 还有两个for应该这样写 for(int i=0;i<tot;i++) for(int j=i+1;j<=tot;j++) 一开始写成O(n^3)了,感觉自己还是太弱了啊。。。。。。。 还有就是第一个for要从0开始,自己写的时候从1开始,导致WA了,各种原因自己慢慢体会 6、还有用到vector容器来清除标记vis,也起到优化时间的作用
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<stack> 5 #include<vector> 6 #include<set> 7 #include<algorithm> 8 using namespace std; 9 #define inf 1<<26 10 #define N 60000 11 int n; 12 int a[N]; 13 int dp[N]; 14 int vis[N]; 15 set<int> s; 16 struct Node 17 { 18 int idd; 19 int num; 20 int rankk; 21 }p[N]; 22 bool cmp1(Node a,Node b) 23 { 24 return a.num<b.num; 25 } 26 bool cmp2(Node a,Node b) 27 { 28 return a.idd<b.idd; 29 } 30 int main() 31 { 32 while(scanf("%d",&n)==1) 33 { 34 for(int i=1;i<=n;i++) 35 scanf("%d",&a[i]); 36 37 //int m=n; 38 int tot=1; 39 p[tot].idd=tot; 40 p[tot++].num=a[1]; 41 for(int i=2;i<=n;i++) 42 { 43 if(a[i]==a[i-1]) 44 continue; 45 else 46 { 47 p[tot].idd=tot; 48 p[tot++].num=a[i]; 49 } 50 } 51 //for(int i=1;i<tot;i++) 52 // printf("---%d %d\n",p[i].idd,p[i].num); 53 54 tot--; 55 56 sort(p+1,p+1+tot,cmp1); 57 58 p[1].rankk=1; 59 int w=2; 60 for(int i=2;i<=tot;i++) 61 { 62 if(p[i].num!=p[i-1].num) 63 { 64 p[i].rankk=w; 65 w++; 66 } 67 else 68 { 69 p[i].rankk=p[i-1].rankk; 70 } 71 } 72 73 sort(p+1,p+1+tot,cmp2); 74 for(int i=1;i<=tot;i++) 75 dp[i]=inf; 76 77 vector<int>v; 78 dp[0]=0; 79 dp[tot]=tot; 80 for(int i=0;i<tot;i++) 81 { 82 int tmp=0; 83 for(int j=i+1;j<=tot;j++) 84 { 85 if(!vis[p[j].rankk]) 86 { 87 v.push_back(p[j].rankk); 88 vis[p[j].rankk]=1; 89 tmp++; 90 } 91 if(dp[i]+tmp*tmp>=dp[tot]) break; 92 dp[j]=min(dp[j],dp[i]+tmp*tmp); 93 } 94 for(int i=0;i<v.size();i++) 95 vis[v[i]]=0; 96 v.clear(); 97 } 98 printf("%d\n",dp[tot]); 99 } 100 return 0; 101 }
标签:
原文地址:http://www.cnblogs.com/UniqueColor/p/4738126.html