SRM 600 DIV1

本文探讨了通过按位讨论和枚举角度的方法解决矩阵匹配问题。首先确定枚举角度,利用状压枚举法处理palindromes,然后通过动态规划计算获得rcnt行的最小代价。详细介绍了如何根据对称性简化计算过程,包括处理不同增益情况下的代价,最终实现高效求解。此外,文章还提供了关键代码段和注释,帮助读者理解算法实现细节。

A

 按位讨论,取最小值;

B

 数据范围不大,首先要确定枚举角度;

 状压枚举palindromes的列比较科学;

 列确定后,目标就是求获得rcnt行的最小代价:

  dp[i][cnt]表示扫描到第i行,已经有cnt个满足要求的最小代价;

 根据对称性,只要扫描n/2行,而从第i行获得j个增益的代价cost[i][j],可以另外处理:

  当考虑cost[i][j]时,根据对称性,实际是考虑2行(i,n-i),从这2行获得增益的情况只有3种:0,1,2,

  然后,讨论每种情况下的代价:

    0, 只需保证列满足要求;

    1, 任一行满足要求,取最小值;

    2, 2行 同时满足要求;

  然后各种特判...

  1 #include <vector>
  2 #include <list>
  3 #include <map>
  4 #include <set>
  5 #include <deque>
  6 #include <stack>
  7 #include <bitset>
  8 #include <algorithm>
  9 #include <functional>
 10 #include <numeric>
 11 #include <utility>
 12 #include <sstream>
 13 #include <iostream>
 14 #include <iomanip>
 15 #include <cstdio>
 16 #include <cmath>
 17 #include <cstdlib>
 18 #include <ctime>
 19 #include <cstring>
 20 using namespace std;
 21 #define maxn (1<<14)
 22 #define INF 4000
 23 #define rep(i,n) for(int i=0 ; i<(n) ; i++ )
 24 class PalindromeMatrix {
 25 public:
 26     int minChange(vector <string>, int, int);
 27 };
 28 vector<int> valid;
 29 int bit[maxn],n,m;
 30 int check(int mask,int len) {
 31     rep (i,len/2) {
 32         int p = mask&(1<<i);
 33         int q = mask&(1<<(len-i-1));
 34         if (p!=q) return 0;
 35     }
 36     return 1;
 37 }
 38 void init() {
 39     rep (i,maxn) {
 40         if ((i<<1)<maxn)bit[i<<1] = bit[i];
 41         if ((i<<1|1)<maxn)bit[i<<1|1] = bit[i]+1;
 42     }
 43     rep (i,(1<<m)) if (check(i,m)) valid.push_back(i);
 44 }
 45 int dp[15][15],cost[15][3];
 46 void init(vector<string> A,int mask) {
 47     rep (i,15) rep (j,15) dp[i][j]=INF;
 48     rep (i,15) rep (j,3) cost[i][j]=INF;
 49     rep (i,n/2) {
 50         string s1 = A[i];
 51         string s2 = A[n-1-i];
 52     //    cout<<"s1:"<<s1<<endl;
 53     //    cout<<"s2:"<<s2<<endl;
 54         int res = 0;
 55         // r=0
 56         rep (j,m) if (mask&(1<<j)) {
 57             if (s1[j]!=s2[j]) res++;
 58         }
 59         cost[i][0]=res;
 60         // r=2
 61         res = 0;
 62         //printf("cal:cost[%d][2]\n",i);
 63         rep (j,m/2) {
 64             int a=j,b=m-1-j;
 65             if ( (mask&(1<<a)) || (mask&(1<<b)) ) {
 66         //        printf("s1[%d]:%c s1[%d]:%c s2[%d]:%c s2[%d]:%c\n",a,s1[a],b,s1[b],a,s2[a],b,s2[b]);
 67                 int tmp = (s1[a]+s2[a]+s1[b]+s2[b]-4*(int)'0');
 68                 tmp = min(tmp,4-tmp);
 69                 res += tmp;
 70             }else {
 71                 if (s1[a]!=s1[b]) res++;
 72                 if (s2[a]!=s2[b]) res++;
 73             }
 74         }
 75         cost[i][2]=res;
 76         // r=1,s1
 77         res=0;
 78         rep (j,m/2) {
 79             int a=j,b=m-1-j;
 80             if (s1[a] != s1[b]) {
 81                 if ( (mask&(1<<a)) && (mask&(1<<b)) ) {
 82                     int tmp = s1[a]+s1[b]+s2[a]+s2[b]-4*'0';
 83                     res += min(tmp,4-tmp);
 84                 } else res ++;
 85             } else {
 86                 if ( (mask&(1<<a)) && (mask&(1<<b)) ) {
 87                     int tmp = s1[a]+s1[b]+s2[a]+s2[b]-4*'0';
 88                     res += min(tmp,4-tmp);
 89                  } else if ( (mask&(1<<a)) ) {
 90                     res += (s1[a]!=s2[a]);
 91                  } else if ( (mask&(1<<b)) ) {
 92                     res += (s1[b]!=s2[b]);
 93                  }
 94             }
 95         }
 96         cost[i][1]=res;
 97         // r=1,s2
 98         res=0;
 99         rep (j,m/2) {
100             int a=j,b=m-1-j;
101             if (s2[a] != s2[b]) {
102                 if ( (mask&(1<<a)) && (mask&(1<<b)) ) {
103                     int tmp = s1[a]+s1[b]+s2[a]+s2[b]-4*'0';
104                     res += min(tmp,4-tmp);
105                 } else res ++;
106             } else {
107                 if ( (mask&(1<<a)) && (mask&(1<<b)) ) {
108                     int tmp = s1[a]+s1[b]+s2[a]+s2[b]-4*'0';
109                     res += min(tmp,4-tmp);
110                  } else if ( (mask&(1<<a)) ) {
111                     res += (s1[a]!=s2[a]);
112                  } else if ( (mask&(1<<b)) ) {
113                     res += (s1[b]!=s2[b]);
114                  }
115             }
116         }
117         cost[i][1]=min(cost[i][1],res);
118     }
119 }
120 void PrintMask(int mask) {//printf("var:%d mask:",mask);
121     while (mask) {
122     //    printf("%d",mask&1?1:0);
123         mask>>=1;
124     }//printf("\n");
125 }
126 int solv(vector<string> A,int nr,int nc) {
127     int ans = INF;
128     rep (s,(1<<m)) if (bit[s]==nc) {
129         PrintMask(s);
130         init(A,s);
131         dp[0][0] = 0;
132         rep (i,n/2) rep (j,nr+1)
133         if (dp[i][j]!=INF) {
134             rep (k,3) {
135                 int nxtj = min(nr,k+j);
136                 dp[i+1][nxtj] = min(dp[i+1][nxtj],dp[i][j]+cost[i][k]);
137             }
138         }
139         ans = min(ans,dp[n/2][nr]);
140     }
141     return ans;
142 }
143 int PalindromeMatrix::minChange(vector <string> A, int nr, int nc) {
144     init();
145     n = A.size();
146     m = A[0].size();
147     int ans= solv(A,nr,nc);
148     return ans;
149 }
View Code

 

C

 刚开始想按b递增考虑,每加入一条线时的增加数应该很好算,后来发现情况非常复杂,很难发现结论.

 题解的结论是从交点个数得到的.

 尝试证明一下:

  加入一条直线时,每产生一个交点,就划分出一个新的区域,最后想象无穷远处有条封闭的边界,与延时到无限远的直线构成新的区域,

  所以结论为  1 + 不同的交点个数.

 

 1 #include <vector>
 2 #include <list>
 3 #include <map>
 4 #include <set>
 5 #include <deque>
 6 #include <stack>
 7 #include <bitset>
 8 #include <algorithm>
 9 #include <functional>
10 #include <numeric>
11 #include <utility>
12 #include <sstream>
13 #include <iostream>
14 #include <iomanip>
15 #include <cstdio>
16 #include <cmath>
17 #include <cstdlib>
18 #include <ctime>
19 
20 using namespace std;
21 
22 class LotsOfLines {
23 public:
24     long long countDivisions(int, int);
25 };
26 int gcd(int a,int b) {
27     if (b==0) return a;
28     return gcd(b,a%b);
29 }
30 long long sum[1201][1201];
31 long long LotsOfLines::countDivisions(int A, int B) {
32     long long ans = 1;
33     A-- , B--;
34     for (int q=1 ; q<=A ; q++ ) {
35         for (int p=1 ; p<=B ; p++ ) {
36             int x = gcd(p,q)==1?1:0;
37             sum[q][p] = sum[q-1][p] + sum[q][p-1] - sum[q-1][p-1] + x;
38         }
39     }
40     for (int a=0 ; a<=A ; a++ ) {
41         for (int b=0 ; b<=B ; b++ ) {
42             ans ++;
43             if (a)
44                 ans += 1 + sum[a][b] + sum[a][B-b];
45         }
46     }
47     return ans;
48 }
49 
50 
51 //Powered by [KawigiEdit] 2.0!
View Code

 

 

转载于:https://www.cnblogs.com/eggeek/p/3536958.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值