首页 > 代码库 > noip2008 真题练习 2017.2.25
noip2008 真题练习 2017.2.25
不是有很多可以说的,记住不能变算边取min
Code
1 #include<iostream> 2 #include<fstream> 3 #include<sstream> 4 #include<cstdio> 5 #include<cctype> 6 #include<cstring> 7 #include<cstdlib> 8 #include<cmath> 9 #include<algorithm>10 #include<queue>11 #include<vector>12 #include<stack>13 #include<map>14 #include<set>15 using namespace std;16 typedef bool boolean;17 #define INF 0xfffffff18 #define smin(a, b) a = min(a, b)19 #define smax(a, b) a = max(a, b)20 21 ifstream fin("word.in");22 ofstream fout("word.out");23 24 int n;25 int c;26 char str[105];27 28 inline void init() {29 fin >> str;30 n = strlen(str);31 }32 33 int counter[30];34 inline void solve() {35 int minv = 1000, maxv = 0;36 memset(counter, 0, sizeof(counter));37 for(int i = 0, ch; i < n; i++) {38 ch = (int) (str[i] - ‘a‘);39 counter[ch]++;40 }41 for(int i = 0; i < 30; i++) {42 if(counter[i] != 0) {43 smin(minv, counter[i]);44 smax(maxv, counter[i]);45 }46 }47 c = maxv - minv;48 if(c < 2) {49 fout << "No Answer" << endl;50 fout << 0 << endl;51 } else if(c == 2 || c == 3) {52 fout << "Lucky Word" << endl;53 fout << c << endl;54 } else {55 int limit = (int)sqrt(c + 0.5);56 for(int i = 2; i <= limit; i++) {57 if(c % i == 0) {58 fout << "No Answer" << endl;59 fout << 0 << endl;60 return;61 }62 }63 fout << "Lucky Word" << endl;64 fout << c << endl;65 }66 }67 68 int main() {69 init();70 solve();71 fin.close();72 fout.close();73 return 0;74 }
记下每个数字所需的火柴数,然后去搜索吧,或者找出上界,枚举两个加数,再判断是否可行。
Code
1 #include<iostream> 2 #include<fstream> 3 #include<sstream> 4 #include<cstdio> 5 #include<cctype> 6 #include<cstring> 7 #include<cstdlib> 8 #include<cmath> 9 #include<algorithm>10 #include<queue>11 #include<vector>12 #include<stack>13 #include<map>14 #include<set>15 using namespace std;16 typedef bool boolean;17 #define INF 0xfffffff18 #define smin(a, b) a = min(a, b)19 #define smax(a, b) a = max(a, b)20 21 ifstream fin("matches.in");22 ofstream fout("matches.out");23 24 int n;25 26 inline void init() {27 fin >> n;28 n -= 4;29 }30 31 const int cost[10] = {6, 2, 5, 5, 4, 5, 6, 3, 7, 6};32 33 int result = 0;34 int buf[25];35 36 int getInt(int from, int end) {37 if(buf[from] == 0 && end - from > 1) return -10000;38 if(buf[from] == 0) return 0;39 int ret = 0;40 for(int i = from; i < end; i++) {41 ret *= 10;42 ret += buf[i];43 }44 return ret;45 }46 47 int check(int top) {48 int res = 0;49 if(top < 3) return 0;50 // if(buf[0] == 0 && buf[1] == 0) return (buf[2] == 0 && top == 3) ? (1) : (0);51 for(int i = 1; i < top - 1; i++) {52 for(int j = i + 1; j < top; j++) {53 int a = getInt(0, i);54 int b = getInt(i, j);55 int c = getInt(j, top);56 if(a + b == c) res++;//, fout << a << "+" << b << "=" << c << endl;;57 }58 }59 return res;60 }61 62 void dfs(int pos, int used) {63 if(used == n) {64 result += check(pos);65 return;66 }67 for(int i = 0; i <= 9; i++) {68 if(used + cost[i] <= n) {69 buf[pos] = i;70 dfs(pos + 1, used + cost[i]);71 }72 }73 }74 75 inline void solve() {76 dfs(0, 0);77 fout << result;78 fin.close();79 fout.close();80 }81 82 int main() {83 init();84 solve();85 return 0;86 }
从下面传上来,等于从上面传下去,原问题就等于从左上角找两条互不相交的路径,简单地是写个dp,f[x0][y0][x1][y1]或者f[dis][x0][x1],然而我先想到的是网络流,将每个点拆成2个点(除去左上角的和右下角那个),中间连一条容量为1,费用为0的有向边。其他边按照题目意思来建。也是容量为1,费用为起点的点权。然后求左上角到右下角流量为2的最大费用流。(noip用网络流?)
Code
1 #include<iostream> 2 #include<fstream> 3 #include<sstream> 4 #include<cstdio> 5 #include<cctype> 6 #include<cstring> 7 #include<cstdlib> 8 #include<cmath> 9 #include<algorithm> 10 #include<queue> 11 #include<vector> 12 #include<stack> 13 #include<map> 14 #include<set> 15 using namespace std; 16 typedef bool boolean; 17 #define inf 0xfffffff 18 #define smin(a, b) a = min(a, b) 19 #define smax(a, b) a = max(a, b) 20 21 typedef class Edge { 22 public: 23 int end; 24 int next; 25 int flow; 26 int cap; 27 int cost; 28 Edge(const int end = 0, const int next = 0, const int flow = 0, const int cap = 0, const int cost = 0):end(end), next(next), flow(flow), cap(cap), cost(cost) { } 29 }Edge; 30 31 typedef class MapManager { 32 public: 33 int ce; 34 int* h; 35 Edge* edge; 36 MapManager():ce(0), h(NULL), edge(NULL) { } 37 MapManager(int points, int limit):ce(0) { 38 h = new int[(const int)(points + 1)]; 39 edge = new Edge[(const int)(limit + 1)]; 40 memset(h, 0, sizeof(int) * (points + 1)); 41 } 42 inline void addEdge(int from, int end, int flow, int cap, int cost) { 43 edge[++ce] = Edge(end, h[from], flow, cap, cost); 44 h[from] = ce; 45 } 46 inline void addDoubleEdge(int from, int end, int cap, int cost) { 47 addEdge(from, end, 0, cap, cost); 48 addEdge(end, from, cap, cap, -cost); 49 } 50 Edge& operator [](int pos) { 51 return edge[pos]; 52 } 53 int reverse(int pos) { 54 return (pos & 1) ? (pos + 1) : (pos - 1); 55 } 56 }MapManager; 57 #define m_begin(g, i) (g).h[(i)] 58 59 ifstream fin("message.in"); 60 ofstream fout("message.out"); 61 62 int n, m; 63 MapManager g; 64 int l; 65 66 inline int pti(int x, int y) { return x * n + y; } 67 inline void init() { 68 fin >> m >> n; 69 g = MapManager(2 * m * n, 8 * m * n); 70 l = m * n; 71 for(int i = 0, a; i < m; i++) { 72 for(int j = 0; j < n; j++) { 73 fin >> a; 74 g.addDoubleEdge(pti(i, j), pti(i, j) + l, 1, 0); 75 if(i < m - 1) g.addDoubleEdge(pti(i, j) + l, pti(i + 1, j), 1, a); 76 if(j < n - 1) g.addDoubleEdge(pti(i, j) + l, pti(i, j + 1), 1, a); 77 } 78 } 79 } 80 81 int* dis; 82 boolean *visited; 83 int* last; 84 int* lase; 85 int* mflow; 86 int cost; 87 queue<int> que; 88 boolean spfa(int s, int t) { 89 memset(dis, 0xf0, sizeof(int) * (2 * l + 1)); 90 memset(visited, false, sizeof(boolean) * (2 * l + 1)); 91 dis[s] = last[s] = lase[s] = 0; 92 que.push(s); 93 mflow[s] = inf; 94 visited[s] = true; 95 while(!que.empty()) { 96 int e = que.front(); 97 que.pop(); 98 visited[e] = false; 99 for(int i = m_begin(g, e); i != 0; i = g[i].next) {100 int& eu = g[i].end;101 if(dis[e] + g[i].cost > dis[eu] && g[i].flow < g[i].cap) {102 dis[eu] = dis[e] + g[i].cost;103 last[eu] = e;104 lase[eu] = i;105 mflow[eu] = min(g[i].cap - g[i].flow, mflow[e]);106 if(!visited[eu] && eu != t) {107 que.push(eu);108 visited[eu] = true;109 }110 }111 }112 }113 if(!dis[t]) return false;114 for(int i = t; i != s; i = last[i]) {115 g[lase[i]].flow += mflow[t];116 g[g.reverse(lase[i])].flow -= mflow[t];117 cost += mflow[t] * g[lase[i]].cost;118 }119 return true;120 }121 122 inline void solve() {123 dis = new int[(const int)(2 * l + 1)];124 visited = new boolean[(const int)(2 * l + 1)];125 last = new int[(const int)(2 * l + 1)];126 lase = new int[(const int)(2 * l + 1)];127 mflow = new int[(const int)(2 * l + 1)];128 cost = 0;129 spfa(l, l - 1);130 spfa(l, l - 1);131 fout << (cost);132 }133 134 int main() {135 init();136 solve();137 return 0;138 }
首先来思考一下,对于单栈排序的要求。
当且仅当存在这种情况不能排序:存在某个数j使得lis[j]大于它左边的某个位置i(i < j)的值lis[i],又大于右边某个位置k(k > j)的值lis[k],且lis[i]>lis[k]。可以随便举点例子2 3 1,2 4 3 1...这里就简单地说明一下,因为排序要是小的在前面,那么在k前面的都得先进栈,因为j在i后面,所以是lis[j]先被弹出栈,但lis[i]应该在它的前面,所以说这种情况不可以。
当然考虑全面点还可以考虑一下其他情况
现在回到双栈排序,对于不能用单栈排序完成的就扔到另一个栈完成...然后就会发现,这是一个二分图染色,对于有序数对(i,j)(i < j)满足上上面的情况,则就在i,j连一条边,因为i,j不能一个栈内排序,所以相连的点的颜色要不同。至于染色的方法可以参考noip2010第三题二分答案中判断的过程。
如果中间任何一个dfs的返回值为false,就说明无法用2个栈排序,按照题目意思输出0。
最后就是按照题目意思,进行一个模拟:现在要把i弹出到输出队列,如果i不在双栈中,就把它及其它前面的元素放到stack[color[j]]中,然后再把它弹出来,否则就看看在哪个栈中,然后把它弹出来。然后题目要你输出什么就怎么输出。
另外还有一个问题,建立二分图的时候如果暴力枚举i,j,k那么时间复杂度是O(n3),可以发现k被重复枚举了很多次,但是我们只需要知道对于数i,在位置j后是否存在比它小的数,于是就提前处以一个exist[i][j],这就可以把时间复杂度将为O(n2)。
(PS:此题数据很水,dfs+暗黑剪枝比这种方法快得多)
Code
1 #include<iostream> 2 #include<fstream> 3 #include<sstream> 4 #include<cstdio> 5 #include<cctype> 6 #include<cstring> 7 #include<cstdlib> 8 #include<cmath> 9 #include<algorithm> 10 #include<queue> 11 #include<vector> 12 #include<stack> 13 #include<map> 14 #include<set> 15 using namespace std; 16 typedef bool boolean; 17 #define INF 0xfffffff 18 #define smin(a, b) a = min(a, b) 19 #define smax(a, b) a = max(a, b) 20 21 #define LOCAL 22 #ifndef LOCAL 23 #define fin cin 24 #define fout cout 25 #else 26 ifstream fin("twostack.in"); 27 ofstream fout("twostack.out"); 28 #endif 29 30 template<typename T>class Matrix{ 31 public: 32 T *p; 33 int lines; 34 int rows; 35 Matrix():p(NULL){ } 36 Matrix(int rows, int lines):lines(lines), rows(rows){ 37 p = new T[(lines * rows)]; 38 } 39 T* operator [](int pos){ 40 return (p + pos * lines); 41 } 42 }; 43 #define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows) 44 45 ///map template starts 46 typedef class Edge{ 47 public: 48 int end; 49 int next; 50 Edge(const int end = 0, const int next = 0):end(end), next(next){} 51 }Edge; 52 typedef class MapManager{ 53 public: 54 int ce; 55 int *h; 56 Edge *edge; 57 MapManager():h(NULL), edge(NULL){ } 58 MapManager(int points, int limit):ce(0){ 59 h = new int[(const int)(points + 1)]; 60 edge = new Edge[(const int)(limit + 1)]; 61 memset(h, 0, sizeof(int) * (points + 1)); 62 } 63 inline void addEdge(int from, int end){ 64 edge[++ce] = Edge(end, h[from]); 65 h[from] = ce; 66 } 67 inline void addDoubleEdge(int from, int end){ 68 addEdge(from, end); 69 addEdge(end, from); 70 } 71 Edge& operator [](int pos) { 72 return edge[pos]; 73 } 74 inline void clear() { 75 delete[] h; 76 delete[] edge; 77 } 78 }MapManager; 79 #define m_begin(g, i) (g).h[(i)] 80 ///map template ends 81 82 int n; 83 int* lis; 84 Matrix<boolean> exist; 85 MapManager g; 86 87 inline void init() { 88 fin >> n; 89 lis = new int[(const int)(n + 1)]; 90 for(int i = 1; i <= n; i++) 91 fin >> lis[i]; 92 } 93 94 inline void init_map() { 95 exist = Matrix<boolean>(n + 1, n + 2); 96 matset(exist, false, sizeof(boolean)); 97 for(int i = 1; i < n; i++) { 98 for(int j = n; j > i; j--) { 99 if(exist[i][j + 1] || lis[j] < lis[i])100 exist[i][j] = true;101 }102 }103 104 g = MapManager(n, 2 * n * n);105 for(int i = 1; i < n; i++) {106 for(int j = i + 1; j <= n; j++) {107 if(lis[j] > lis[i] && exist[i][j])108 g.addDoubleEdge(i, j);109 }110 }111 }112 113 int* color;114 boolean dfs(int node, int val) {115 if(color[node] != -1) return color[node] == val;116 else color[node] = val;117 for(int i = m_begin(g, node); i != 0; i = g[i].next) {118 int& e = g[i].end;119 if(!dfs(e, val ^ 1)) return false; 120 }121 return true;122 }123 124 inline void coloring() {125 color = new int[(const int)(n + 1)];126 memset(color, -1, sizeof(int) * (n + 1));127 for(int i = 1; i <= n; i++) {128 if(color[i] == -1)129 if(!dfs(i, 0)) {130 fout << 0 << endl;131 exit(0);132 }133 }134 g.clear();135 delete[] exist.p;136 }137 138 int *s[2];139 int tops[2] = {0, 0};140 int *status;141 char its[3] = {‘a‘, ‘c‘};142 inline void solve() {143 for(int i = 0; i < 2; i++)144 s[i] = new int[(const int)(n + 1)];145 status = new int[(const int)(n + 1)];146 memset(status, -1, sizeof(int) * (n + 1));147 for(int i = 1, j = 1; i <= n; i++) {148 if(status[i] == -1) {149 while(j <= n && lis[j] != i) {150 s[color[j]][tops[color[j]]++] = lis[j];151 status[lis[j]] = color[j];152 fout << its[color[j]] << " ";153 j++;154 }155 status[lis[j]] = color[j];156 fout << its[color[j]] << " " << (char) (its[color[j]] + 1) << " ";157 j++;158 } else {159 --tops[status[i]];160 fout << (char) (its[status[i]] + 1) << " ";161 }162 }163 #ifdef LOCAL164 fin.close();165 fout.close();166 #endif167 }168 169 int main() {170 init();171 init_map();172 coloring();173 solve();174 return 0;175 }
noip2008 真题练习 2017.2.25