Educational Codeforces Round 29(6/7)

1、Quasi-palindrome

  题意:问一个字符串(你可以添加前导‘0’或不添加)是否是回文串

  思路:将给定的字符串的前缀‘0’和后缀‘0’都去掉,然后看其是否为回文串

 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\n");
16     else printf("NO\n");
17 
18     return 0;
19 }
View Code

2、Kayaking

  题意:给出2*n个人的体重,有n-1辆双人车和2辆单人车,问每辆双人车上两个人的体重之差的和最小是多少

  思路:先把体重从小到大排序,然后枚举不坐双人车的两个人,算出剩下的人的最小体重差的和,取最小值。

 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\n", sum);
41     return 0;
42 }
View Code

3、1-2-3

  题意:给出Alice和Bob的出拳依据及他们第一次的出拳,问k轮后Alice和Bob的得分

  思路:找到循环节。

  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\n", 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\n", suma, sumb);
116     }
117     return 0;
118 }
View Code

 4、Yet Another Array Queries Problem

  题意:对数组进行两种操作:1是将某个区间内的数左移(最左边移到的移到最右边);2是将某个区间内的数反转。给出初始数组和若干操作后,问若干下标位置的数是谁

  思路:对每一个所询问的下边的数,从最后一次操作向前找其对应的初始数组的下标。

 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("\n");
39     return 0;
40 }
View Code

5、Turn Off The TV

  题意:有若干个区间,现在需要确定是否有多余的区间,使得在去掉这些区间后原本至少被一个区间覆盖的总长度不会减少。若存在,输出任意一个满足条件的区间的编号。

  思路:把区间按左端点排序,如果当前区间的右端点小于等于当前的最右端,则该区间就是多余区间;否则,如果当前区间的左端点比当前最右端还要大,则更新当前区间最左端和当前区间最右端;否则,如果当前区间的下一个区间和当前最左端和最右端构成的区间能够覆盖当前区间,则当前区间就是多余区间。

 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\n");
54     else printf("%d\n", tv[ans].idx);
55     return 0;
56 }
View Code

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,即题目所要求的)

  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\n");
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\n");
171         //else printf("%d\n", totcost);//之前flag判断是否可行也可用该步来替换
172         printf("%d\n", totcost);
173     }
174     return 0;
175 }
View Code

 

转载于:https://www.cnblogs.com/ivan-count/p/7679644.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值