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 0xfffffff
18 #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 0xfffffff
18 #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 LOCAL
164     fin.close();
165     fout.close();
166 #endif
167 }
168 
169 int main() {
170     init();
171     init_map();
172     coloring();
173     solve();
174     return 0;
175 }
posted @ 2017-02-25 17:17  阿波罗2003  阅读(274)  评论(0编辑  收藏  举报