2014 ACM/ICPC Asia Regional Xi'an Online

03 hdu5009

状态转移方程很好想,dp[i] = min(dp[j]+o[j~i]^2,dp[i]) ,o[j~i]表示从j到i颜色的种数。

普通的O(n*n)是会超时的,可以想到o[]最大为sqrt(n),问题是怎么快速找到从i开始往前2种颜色、三种、四种。。。o[]种的位置。

离散化之后,可以边走边记录某个数最后一个出现的位置,初始为-1,而所要求的位置就等于

if(last[a[i]]==-1) 该数没有出现过,num[i][1] = i,num[i][j+1] = num[i-1][j];

else  last[a[i]]之前 num[i][1] = i,num[i][j+1] = num[i-1][j],之后num[i][j]= num[i-1][j];

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<vector>
 7 #include<cmath>
 8 #include<queue>
 9 #include<set>
10 #include<map>
11 using namespace std;
12 #define N 50010
13 #define LL long long
14 #define INF 0xfffffff
15 const double eps = 1e-8;
16 const double pi = acos(-1.0);
17 const double inf = ~0u>>2;
18 int a[N];
19 int dp[N];
20 int num[2][300],last[N];
21 map<int,int>f;
22 int main()
23 {
24     int i,j,n;
25     while(scanf("%d",&n)!=EOF)
26     {
27         f.clear();
28         int g =0 ;
29         for(i = 1; i<= n ;i++)
30         {
31             scanf("%d",&a[i]);
32             if(!f[a[i]])
33             {
34                 f[a[i]] = ++g;
35                 a[i] = g;
36             }
37             else a[i] = f[a[i]];
38         }
39         for(i = 1; i <= n; i++)
40         dp[i] = INF;
41         memset(last,-1,sizeof(last));
42         memset(num,0,sizeof(num));
43         int k = sqrt(n*1.0)+1;
44         int tk = 1;
45         dp[1] = 1;
46         last[a[1]] = 1;
47         num[1][1] = 1;
48         dp[0] = 0;
49         for(i = 2; i <= n ;i++)
50         {
51             if(last[a[i]]==-1)
52             {
53                 tk+=1;
54                 num[i%2][1] = i;
55                 for(j = 1; j <= min(tk-1,k-1) ; j++)
56                 num[i%2][j+1] = num[(i-1)%2][j];
57             }
58             else
59             {
60 
61                 num[i%2][1] = i;
62                 for(j = 1; j < min(k,tk) ; j++)
63                 {
64                     if(last[a[i]]==num[(i-1)%2][j]) break;
65                     num[i%2][j+1] = num[(i-1)%2][j];
66                 }
67                 for(int g = j+1 ; g <= min(tk,k) ; g++)
68                 num[i%2][g] = num[(i-1)%2][g];
69             }
70             last[a[i]] = i;
71             for(j = 1; j <= min(k,tk); j++)
72             {
73                 int po = num[i%2][j+1];
74                 dp[i] = min(dp[i],dp[po]+j*j);
75                // cout<<dp[po]<<" "<<po<<endl;
76             }
77         }
78         printf("%d
",dp[n]);
79 
80     }
81     return 0;
82 }
View Code

09 hdu5015

构造矩阵

先构造出1*(n+2)的矩阵 (233, 233+a1, 233+a1+a2, 233+a1+a2+a3, ..., 233+a1+a2+..+an, 1),表示第一列上的值。

此矩阵为A,然后想要使A*B = C,C为第二列的值,所以B可以为

10 10 10 10 10 .......0

0   1    1   1   1........0

0   0    1   1   1........0

0   0    0   1   1........0

0   0    0   0   1........0

3   3    3   3   3........1

然后快速幂就可以了。。

  1 #include <iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<stdlib.h>
  6 #include<vector>
  7 #include<cmath>
  8 #include<queue>
  9 #include<set>
 10 using namespace std;
 11 #define N 12
 12 #define LL __int64
 13 #define INF 0xfffffff
 14 const double eps = 1e-8;
 15 const double pi = acos(-1.0);
 16 const double inf = ~0u>>2;
 17 #define mod 10000007
 18 struct Mat
 19 {
 20     LL mat[N][N];
 21 };
 22 int n;
 23 int a[N];
 24 Mat operator * (Mat a,Mat b)
 25 {
 26     Mat c;
 27     memset(c.mat,0,sizeof(c.mat));
 28     int i,j,k;
 29     for(k =0 ; k < n ; k++)
 30     {
 31         for(i = 0 ; i < n ; i++)
 32         {
 33             if(a.mat[i][k]==0) continue;//优化
 34             for(j = 0 ; j < n ; j++)
 35             {
 36                 if(b.mat[k][j]==0) continue;//优化
 37                 c.mat[i][j] = (c.mat[i][j]+(a.mat[i][k]*b.mat[k][j])%mod)%mod;
 38             }
 39         }
 40     }
 41     return c;
 42 }
 43 Mat operator ^(Mat a,int k)
 44 {
 45     Mat c;
 46     int i,j;
 47     for(i =0 ; i < n ; i++)
 48         for(j = 0; j < n ; j++)
 49             c.mat[i][j] = (i==j);
 50     for(; k ; k >>= 1)
 51     {
 52         if(k&1) c = c*a;
 53         a = a*a;
 54     }
 55     return c;
 56 }
 57 int main()
 58 {
 59     int m,i,j;
 60     Mat c;
 61     while(scanf("%d%d",&n,&m)!=EOF)
 62     {
 63         memset(c.mat,0,sizeof(c.mat));
 64         for(i = 0 ; i <= n; i++)
 65         {
 66             c.mat[0][i] = 10;
 67             for(j = 1 ; j <= i ; j++)
 68                 c.mat[j][i] = 1;
 69         }
 70         for(i = 0 ; i <= n ; i++)
 71             c.mat[n+1][i] = 3;
 72         c.mat[n+1][n+1] = 1;
 73         LL s = 233;
 74         Mat ans;
 75         memset(ans.mat,0,sizeof(ans));
 76         ans.mat[0][0] = s;
 77         for(i = 1; i <= n; i++)
 78         {
 79             scanf("%d",&a[i]);
 80             s+=a[i];
 81             s%=mod;
 82             ans.mat[0][i] = s;
 83         }
 84         ans.mat[0][n+1] = 1;
 85         int tn = n;
 86         n+=2;
 87         if(m>1)
 88         ans = ans*(c^(m-1));
 89 //        for(i = 0 ; i < n ; i++)
 90 //            {for(j = 0; j< n ; j++)
 91 //        cout<<c.mat[i][j]<<" ";
 92 //        puts("");
 93 //            }
 94 //        for(i = 0 ; i < n ; i++)
 95 //        {
 96 //            for(j = 0; j < n ; j++)
 97 //                cout<<ans.mat[i][j]<<" ";
 98 //            puts("");
 99 //        }
100         printf("%I64d
",ans.mat[0][tn]);
101     }
102     return 0;
View Code
原文地址:https://www.cnblogs.com/shangyu/p/3971984.html