1、Quasi-palindrome
题意:问一个字符串(你可以添加前导‘0’或不添加)是否是回文串
思路:将给定的字符串的前缀‘0’和后缀‘0’都去掉,然后看其是否为回文串
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 using namespace std; 3 int main() 4 { 5 int num; 6 scanf("%d", &num); 7 while (num / 10 != 0 && num % 10 == 0) num /= 10; 8 int tmp = 0; 9 int tnum = num; 10 while (tnum) 11 { 12 tmp = tmp * 10 + tnum % 10; 13 tnum /= 10; 14 } 15 if (tmp == num) printf("YES "); 16 else printf("NO "); 17 18 return 0; 19 }
2、Kayaking
题意:给出2*n个人的体重,有n-1辆双人车和2辆单人车,问每辆双人车上两个人的体重之差的和最小是多少
思路:先把体重从小到大排序,然后枚举不坐双人车的两个人,算出剩下的人的最小体重差的和,取最小值。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 int wt[120]; 5 const int INF = 1e9; 6 int main() 7 { 8 int n; 9 scanf("%d", &n); 10 for (int i = 1; i <= 2 * n; i++) 11 { 12 scanf("%d", &wt[i]); 13 } 14 sort(wt + 1, wt + 2 * n + 1); 15 16 int sum = INF; 17 for (int i = 1; i < 2 * n; i++) 18 { 19 for (int j = i + 1; j <= 2 * n; j++) 20 { 21 int tsum = 0; 22 for (int k = 1; k <= 2 * n;) 23 { 24 while(k == i||k==j) 25 { 26 k++; 27 } 28 int w1 = wt[k]; 29 k++; 30 while(k == j||k==i) 31 { 32 k++; 33 } 34 tsum += wt[k] - w1; 35 k++; 36 } 37 sum = min(sum, tsum); 38 } 39 } 40 printf("%d ", sum); 41 return 0; 42 }
3、1-2-3
题意:给出Alice和Bob的出拳依据及他们第一次的出拳,问k轮后Alice和Bob的得分
思路:找到循环节。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<map> 3 using namespace std; 4 int alice[3][3]; 5 int bob[3][3]; 6 map<pair<int, int>, int>mp; 7 map<int, pair<int, int> >score; 8 int a, b; 9 long long k; 10 int main() 11 { 12 scanf("%I64d%d%d", &k, &a, &b); 13 for (int i = 0; i < 3; i++) 14 { 15 for (int j = 0; j < 3; j++) 16 { 17 scanf("%d", &alice[i][j]); 18 alice[i][j]--; 19 } 20 } 21 for (int i = 0; i < 3; i++) 22 { 23 for (int j = 0; j < 3; j++) 24 { 25 scanf("%d", &bob[i][j]); 26 bob[i][j]--; 27 } 28 } 29 int apoint = 0, bpoint = 0; 30 int prea, preb; 31 int kk = 0; 32 int T,ta,tb,st; 33 a--, b--; 34 while (kk < k) 35 { 36 if (kk == 0) 37 { 38 prea = a; 39 preb = b; 40 if (a == 0 && b == 2|| a== 2 && b == 1||a==1&&b==0) apoint++; 41 else if (b == 0 && a == 2 || b == 2 && a == 1 || b == 1 && a == 0)bpoint++; 42 mp[make_pair(a, b)] = ++kk; 43 } 44 else 45 { 46 int aa = alice[prea][preb], bb = bob[prea][preb]; 47 if (st=mp[make_pair(aa, bb)]) 48 { 49 T = kk - st + 1; 50 pair<int, int>t1, t2; 51 if (T == 1) 52 { 53 t1 = score[st]; 54 if (st > 1) 55 { 56 t2 = score[st - 1]; 57 ta = t1.first - t2.first; 58 tb = t1.second - t2.second; 59 } 60 else 61 { 62 ta = t1.first, tb = t1.second; 63 } 64 } 65 else 66 { 67 if (st > 1) 68 { 69 t1 = score[st - 1]; 70 t2 = score[kk]; 71 ta = t2.first - t1.first; 72 tb = t2.second - t1.second; 73 } 74 else 75 { 76 t1 = score[kk]; 77 ta = t1.first, tb = t1.second; 78 } 79 } 80 break; 81 } 82 if (aa == 0 && bb == 2 || aa == 2 && bb == 1 || aa == 1 && bb == 0) apoint++; 83 else if (bb == 0 && aa == 2 || bb == 2 && aa == 1 || bb == 1 && aa == 0)bpoint++; 84 mp[make_pair(aa, bb)] = ++kk; 85 prea = aa, preb = bb; 86 } 87 score[kk] = make_pair(apoint, bpoint); 88 } 89 if (kk == k) printf("%d %d ", apoint, bpoint); 90 else 91 { 92 long long suma = 0, sumb = 0; 93 if (st == 1) suma += 1ll*k / T*ta, sumb += 1ll*k / T*tb; 94 else 95 { 96 pair<int, int>tmp = score[st - 1]; 97 suma += tmp.first, sumb += tmp.second; 98 k -= st-1; 99 suma += 1ll * k / T*ta, sumb += 1ll * k / T*tb; 100 } 101 if (k%T) 102 { 103 if (st == 1) 104 { 105 pair<int, int>t = score[k%T]; 106 suma += t.first, sumb += t.second; 107 } 108 else 109 { 110 pair<int, int>t1 = score[st-1]; 111 pair<int, int>t2 = score[k%T+st-1]; 112 suma += t2.first - t1.first, sumb += t2.second - t1.second; 113 } 114 } 115 printf("%I64d %I64d ", suma, sumb); 116 } 117 return 0; 118 }
4、Yet Another Array Queries Problem
题意:对数组进行两种操作:1是将某个区间内的数左移(最左边移到的移到最右边);2是将某个区间内的数反转。给出初始数组和若干操作后,问若干下标位置的数是谁
思路:对每一个所询问的下边的数,从最后一次操作向前找其对应的初始数组的下标。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 using namespace std; 3 int a[200010]; 4 struct node 5 { 6 int ff; 7 int ll; 8 int rr; 9 }qq[200010]; 10 int main() 11 { 12 int n, q, m; 13 scanf("%d%d%d", &n, &q, &m); 14 for (int i = 1; i <= n; i++) scanf("%d", &a[i]); 15 for (int i = 1; i <= q; i++) scanf("%d%d%d", &qq[i].ff, &qq[i].ll, &qq[i].rr); 16 for (int i = 1; i <= m; i++) 17 { 18 int pos; 19 scanf("%d", &pos); 20 for (int j = q; j >= 1; j--) 21 { 22 if (pos >= qq[j].ll&&pos <= qq[j].rr) 23 { 24 if (qq[j].ff == 1) 25 { 26 if (pos > qq[j].ll) pos--; 27 else pos = qq[j].rr; 28 } 29 else 30 { 31 pos = qq[j].rr - (pos - qq[j].ll); 32 } 33 } 34 } 35 if (i > 1) printf(" "); 36 printf("%d", a[pos]); 37 } 38 printf(" "); 39 return 0; 40 }
5、Turn Off The TV
题意:有若干个区间,现在需要确定是否有多余的区间,使得在去掉这些区间后原本至少被一个区间覆盖的总长度不会减少。若存在,输出任意一个满足条件的区间的编号。
思路:把区间按左端点排序,如果当前区间的右端点小于等于当前的最右端,则该区间就是多余区间;否则,如果当前区间的左端点比当前最右端还要大,则更新当前区间最左端和当前区间最右端;否则,如果当前区间的下一个区间和当前最左端和最右端构成的区间能够覆盖当前区间,则当前区间就是多余区间。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 struct node 5 { 6 int ll; 7 int rr; 8 int idx; 9 }tv[200010]; 10 bool Cmp(const node&a, const node&b) 11 { 12 if (a.ll == b.ll) return a.rr > b.rr; 13 else return a.ll < b.ll; 14 } 15 int main() 16 { 17 int n; 18 scanf("%d", &n); 19 for (int i = 0; i < n; i++) 20 { 21 scanf("%d%d", &tv[i].ll, &tv[i].rr); 22 tv[i].idx = i + 1; 23 } 24 sort(tv, tv + n, Cmp); 25 int ans = -1; 26 int tl = tv[0].ll, tr = tv[0].rr; 27 for (int i = 1; i < n; i++) 28 { 29 if (tv[i].rr <= tr) 30 { 31 ans = i; 32 break; 33 } 34 else if (tv[i].ll > tr) 35 { 36 tl = tv[i].ll; 37 tr = tv[i].rr; 38 } 39 else 40 { 41 if (i + 1 < n&&tv[i + 1].ll <= tr+1&&tv[i + 1].rr >= tv[i].rr) 42 { 43 ans = i; 44 break; 45 } 46 else 47 { 48 tl = tv[i].ll; 49 tr = tv[i].rr; 50 } 51 } 52 } 53 if (ans == -1) printf("-1 "); 54 else printf("%d ", tv[ans].idx); 55 return 0; 56 }
6、Almost Permutation
题意:你现在知道若干区间内的数是大于等于某一个数还是小于等于某一个数,然后定义cost为数组中每个数出现的次数的平方和,问最小的cost.
思路:最小费用最大流。当所有条件都符合时(没有矛盾),将源点和每个index相连,容量为1,花费为0;将每个index和该index能够填的数字相连,容量为1,花费为0;对于每个数字,和汇点连n条边,容量1,花费为1、3、5、……、n*n-(n-1)(n-1)(如果当前这个数字出现k次,则需要向汇点连k条边,由于最小费用,肯定取最小花费的k条,由于前x条花费之和=x^2,即题目所要求的)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 using namespace std; 6 int maxlv[55]; 7 int minlv[55]; 8 int cnt[55]; 9 struct pp 10 { 11 int l; 12 int r; 13 int len; 14 }p[55]; 15 16 //最小费用最大流模板 17 #define MAXN 120 18 #define MAXM (2500*2+50)*2+100 19 #define INF 0x3f3f3f3f 20 using namespace std; 21 struct Edge 22 { 23 int from, to, cap, flow, cost, next; 24 Edge(int fr = 0, int tt = 0, int ca = 0, int fl = 0, int ct = 0, int nt = 0) :from(fr), to(tt), cap(ca), flow(fl), cost(ct), next(nt) 25 { 26 }; 27 }; 28 Edge edge[MAXM]; 29 int Head[MAXN], edgenum; 30 int pre[MAXN];//记录增广路径上 到达点i的边的编号 31 int dist[MAXN]; 32 bool vis[MAXN]; 33 int N;//点数 34 //int M;//边数 35 int source, sink;//超级源点 超级汇点 36 void init(int numnode,int st,int sk) 37 { 38 N = numnode, source = st, sink = sk; 39 edgenum = 0; 40 memset(Head, -1, sizeof(Head)); 41 } 42 void addEdge(int u, int v, int w, int c) 43 { 44 //Edge E1 = { u, v, w, 0, c, head[u] }; 45 //edge[edgenum] = E1; 46 edge[edgenum] = Edge(u, v, w, 0, c, Head[u]); 47 Head[u] = edgenum++; 48 //Edge E2 = { v, u, 0, 0, -c, head[v] }; 49 //edge[edgenum] = E2; 50 edge[edgenum] = Edge(v, u, 0, 0, -c, Head[v]); 51 Head[v] = edgenum++; 52 } 53 bool SPFA(int s, int t)//寻找花销最少的路径 54 { 55 //跑一遍SPFA 找s——t的最少花销路径 且该路径上每一条边不能满流 56 //若存在 说明可以继续增广,反之不能 57 queue<int> Q; 58 memset(dist, INF, sizeof(dist)); 59 memset(vis, false, sizeof(vis)); 60 memset(pre, -1, sizeof(pre)); 61 dist[s] = 0; 62 vis[s] = true; 63 Q.push(s); 64 while (!Q.empty()) 65 { 66 int u = Q.front(); 67 Q.pop(); 68 vis[u] = false; 69 for (int i = Head[u]; i != -1; i = edge[i].next) 70 { 71 Edge E = edge[i]; 72 if (dist[E.to] > dist[u] + E.cost && E.cap > E.flow)//可以松弛 且 没有满流 73 { 74 dist[E.to] = dist[u] + E.cost; 75 pre[E.to] = i;//记录前驱边 的编号 76 if (!vis[E.to]) 77 { 78 vis[E.to] = true; 79 Q.push(E.to); 80 } 81 } 82 } 83 } 84 return pre[t] != -1;//可达返回true 85 } 86 void MCMF(int s, int t, int &cost, int &flow) 87 { 88 flow = 0;//总流量 89 cost = 0;//总费用 90 while (SPFA(s, t))//每次寻找花销最小的路径 91 { 92 int Min = INF; 93 //通过反向弧 在源点到汇点的最少花费路径 找最小增广流 94 for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) 95 { 96 Edge E = edge[i]; 97 Min = min(Min, E.cap - E.flow); 98 } 99 //增广 100 for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]) 101 { 102 edge[i].flow += Min; 103 edge[i ^ 1].flow -= Min; 104 cost += edge[i].cost * Min;//增广流的花销 105 } 106 flow += Min;//总流量累加 107 } 108 } 109 110 int main() 111 { 112 int n,q; 113 scanf("%d%d", &n, &q); 114 for (int i = 1; i <= n; i++) maxlv[i] = n, minlv[i] = 1; 115 bool flag = true; 116 for (int i = 1; i <= q; i++) 117 { 118 int type, li, ri, vi; 119 scanf("%d%d%d%d", &type, &li, &ri, &vi); 120 if (!flag)continue; 121 if (type == 1) 122 { 123 for (int j = li; j <= ri; j++) 124 { 125 if (minlv[j] < vi) minlv[j] = vi; 126 if (minlv[j] > maxlv[j]) 127 { 128 flag = false; 129 break; 130 } 131 } 132 } 133 else 134 { 135 for (int j = li; j <= ri; j++) 136 { 137 if (maxlv[j] > vi) maxlv[j] = vi; 138 if (maxlv[j] < minlv[j]) 139 { 140 flag = false; 141 break; 142 } 143 } 144 } 145 } 146 if (!flag) printf("-1 "); 147 else 148 { 149 init(2 * n + 2, 0, 2 * n + 1); 150 for (int i = 1; i <= n; i++) 151 { 152 addEdge(0, i, 1, 0); 153 } 154 for (int i = 1; i <= n; i++) 155 { 156 for (int j = minlv[i]; j <= maxlv[i]; j++) 157 { 158 addEdge(i, n + j, 1, 0); 159 } 160 } 161 for (int i = n + 1; i <= 2 * n; i++) 162 { 163 for (int j = 1; j <= n; j++) 164 { 165 addEdge(i, 2 * n + 1, 1, j*j - (j - 1)*(j - 1)); 166 } 167 } 168 int totflow = 0, totcost = 0; 169 MCMF(source, sink, totcost, totflow); 170 //if (totcost < n) printf("-1 "); 171 //else printf("%d ", totcost);//之前flag判断是否可行也可用该步来替换 172 printf("%d ", totcost); 173 } 174 return 0; 175 }