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 }
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!