3.26-3.31【cf补题+其他】

 

计蒜客)翻硬币

//暴力匹配

#include<cstdio>
#include<cstring>
#define CLR(a, b) memset((a), (b), sizeof((a)))
using namespace std;
int n, m, t;
int main() {
    int i, j, x;
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        int g[n][m];
        CLR(g, 0);
        for(i = 0; i < n; ++i) {
            for(j = 0; j < m; ++j) {
                scanf("%d", &g[i][j]);
            }
        }
        int f = 1;
        bool mk = 0;
        for(i = 1; i < n && f; ++i) {
            mk = g[i][0] != g[0][0];
            for(j = 0; j < m && f; ++j) {
                if(g[i][j] != g[0][j] ^ mk) {
                    f = 0;
                }
            }
        }
        puts(f ? "YES" : "NO");
    }
}

Educational Codeforces Round 18

codeforces 792A - New Bus Route

官方题解

At first let's notice that if there exists such triple ai, aj and ak that ai < aj < ak, then |ak - ai| > |aj - ai| and |ak - ai| > |ak - aj|.

Thus we can sort all numbers and check only adjacent ones. There are exactly n - 1 of such pairs. The only thing left is to find minimal distance of all pairs and count pairs with that distance.

Overall complexity: O(n logn)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const ll inf = 2e9+5;
int n;
int a[200005];
int main() {
    scanf("%d", &n);
    int i, j;
    for(i = 0; i < n; ++i)
        scanf("%d", &a[i]);
    sort(a, a+n);
    ll ans = inf;
    ll cnt = 0, t;
    for(i = 1; i < n; ++i) {
        t = abs(a[i] - a[i-1]);
        if(t < ans) { ans = t; cnt = 1; }
        else if(t == ans) cnt++;
    }
    printf("%I64d %I64d
", ans, cnt);
}
/*
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const ll inf = 2e9+5;
const int N = 2e5+5;
int n, k;
int ans;
ll a[N];
ll c[N][3];
void init(ll n, ll m) {
    ll i, j;
    memset(c,0,sizeof(c));
    for(i = 0; i <= m; i++)
     c[0][i] = c[1][i] = 1;
    for(i = 0; i <= m; i++)
     c[i][i] = 1;
    for(i = 0; i <= n; i++)
     c[i][0] = 1;
    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= m; j++)
        {
            if(i != j)
            c[i][j] = (c[i-1][j] + c[i-1][j-1]);
        }
    }
}
int main() {
    init(N-1, 2);
    scanf("%d", &n);
    int i, j;
    ll mi = inf;
    ll cnt = 0;
    for(i = 0; i < n; ++i) scanf("%I64d", &a[i]);
    sort(a, a+n);
    for(i = 1; i < n; ++i) {
        ll x = a[i] - a[i-1];
        if(x < mi) mi = x;
    }
    ll ss = 0, s = 0;
    for(i = 1; i < n; ++i) {
        cnt = 0;
        if(a[i] == a[i-1]) {
            while(a[i] == a[i-1] && i < n) {cnt++;i++;}
            s = c[cnt+1][2];
            ss += s;
        }
        else if(a[i] - a[i-1] == mi) ss++;
    }
    printf("%I64d %I64d
", mi, ss);
    return 0;
}
*/

codeforces 792B - Counting-out Rhyme

官方题解:The task was just about implementing algorithm described in statement.

This is one of many possible ways of doing this. Firstly you should notice that doing ai iterations in i-th step is equal to doing ai mod (n - i) iterations (0-based numbering). That is less than n.

Now fill array of length n with ones and create pointer to current leader. Then on i-th step move pointer to the right (from cell n - 1 proceed to 0) till you encounter ai mod (n - i) ones. When finished, write 0 to this cell and move pointer to next cell which contains 1.

Overall complexity: O(n2).

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
#define lson rt*2
#define rson rt*2+1
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const ll inf = 2e9+5;
const int N = 2e5+5;
int n, k;
int ans;
vector <int > ve;
int main() {
    scanf("%d%d", &n, &k);
    int i, x;
    for(i = 1; i <= n; ++i) ve.push_back(i);
    int t = 0;
    for(i = 0; i < k; ++i, n--) {
        scanf("%d", &x);
        t = (t+x) % n;
        printf("%d ", ve[t]);
        ve.erase(ve.begin() + t);
    }
    return 0;
}

codeforces 792C. Divide by Three

官方题解:

Let's declare a function which takes number as a string and erases minimal number of digits in substring from 2-nd to last character to obtain beautiful number.

Note that if the answer for given string exists, then this function will erase no more than 2 digits. If the number is divisible by 3 then sum of its digits is also divisible by 3. So here are the only options for the function:

  • Sum of digits is already equal to 0 modulo 3. Thus you don't have to erase any digits.
  • There exists such a digit that equals sum modulo 3. Then you just have to erase this digit.
  • All of the digits are neither divisible by 3, nor equal to sum modulo 3. So two of such digits will sum up to number, which equals sum modulo 3 ((2 + 2) mod 3 = 1, (1 + 1) mod 3 = 2).

Let positions of non-zero numbers be a1, a2, ..., ak. Then you can easily see that its enough to check only three function outputs: on substrings [a1..n], [a2..n] и [a3..n]. We imply that all digits to the left of the taken non-zero digit are erased. As we can erase no more than 2 digits, these options will cover all the cases.

If there exists no answer for any of substrings, than you need to check if the number contains 0 — it will be answer in that case. If there is no 0, then answer is  - 1.

Otherwise the answer is the function output of maximal length.

Overall complexity: O(n).

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
string a, b, c;
int ss(string d) {
    int len = d.length();
    int sum = 0;
    for(int i = 0; i < len; ++i)
        sum = (sum + d[i] - '0') % 3;
    return sum | !d.length();//进行删除数字之后,可能删光了,比如11,删去两次 1
}
void change(string & r) {
    while(r[0] == '0' && r.length() > 1)
        r.erase(0, 1);//进行删除之后,判断并删去前导零
}
int main(){
    cin >> a;
    int x = ss(a);
    int y = 3 - x;
    int s1 = 1, s2 = 2;
    b = c = a;
    for(int i = a.length() - 1; i >= 0; --i) {
        if((a[i] - '0') % 3 == x && s1) { b.erase(i, 1); s1--; }
        if((a[i] - '0') % 3 == y && s2) { c.erase(i, 1); s2--; }
    }
    change(b);  change(c);
    s1 = ss(b);  s2 = ss(c);
    if(s1 && s2) puts("-1");
    else {
        if(c.length() > b.length() && !s2 || s1)
            b = c;
        cout << b << endl;
    }
}

codeforces 792 D. Paths in a Complete Binary Tree

官方题解:

In this editorial x represents the number of vertex we are currently in.

Let k be the maximum integer number such that x is divisible by 2k (or the number of zeroes at the end of the binary representation of x). It is easy to prove that if k = 0, then x is a leaf; if k = 1, then both children of x are leaves, and so on. Even more, the difference between x and any of his children is exactly 2k - 1. So to traverse to the left child, we have to subtract 2k - 1 from x (if x is not a leaf), and to traverse to the right child, we add 2k - 1 to x.

How can we process traversions up? Let y be the number of the parent node. y has exactly k + 1 zeroes at the end of its binary representation, so to traverse from y to x, we need to either add or subtract 2k from y. And to traverse from x to y we also have to either subtract or add 2k to x. One of these operations will lead us to the number divisible by 2k + 1 and not divisible by 2k + 2, and we need to choose this operation.

Time complexity is .

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
ll n, q, u, x, y;
char s[N];
int main(){
    scanf("%I64d%I64d", &n, &q);
    while(q--) {
        scanf("%I64d ", &u);
        scanf("%s", s);
        int len = strlen(s);
        for(int i = 0; i < len; ++i) {
            if(s[i] == 'U') {
                if(u != (n+1)/2) {
                    x = u & (-u);
                    y = (u-x) & (x-u);
                    if((x << 1) < y || !y)
                        u += x;
                    else u -= x;
                    //100:4 , 1000:8 , 1100:12
                    //4:  x = 4, y = 0
                    //12: x = 4, y = 8
                    //U(4 或 12) = 8;
                    //我就打个草稿orz
                    //5: x = 1, y = 4
                    //7: x = 1, y = 2
                    //U(5 或 7) = 6;
                }
            }
            else if(s[i] == 'L') {
                if(u % 2 == 0) {
                    x = u >> 1;
                    u -= x & (-x);
                }
            }
            else {
                if(u % 2 == 0) {
                    x = u >> 1;
                    u += x & (-x);
                }
            }
        }
        printf("%I64d
", u);
    }
}

codeforces 792 E. Colored Balls

官方题解:

If we want to divide all balls from some box into k sets with sizes x and x + 1 (and there are ai balls in this box), then either or . So the solution will be like that:

  1. Iterate over the possible sizes of sets x (from 1 to , or to some constant — in our solution it's 40000) and check if we can divide all balls into sets with sizes x and x + 1,
  2. Then iterate over the number of sets k, calculate the sizes of sets if we want to divide the first box exactly into k sets and try to divide balls from all other boxes into sets of these sizes.

If we want to divide ai balls from the same box into k sets, then the sizes will be and ; but if , then we also have to check if sizes can be and .

If we fix sizes x and x + 1 and we want to check whether we can divide a box with ai balls into sets with these sizes (and to get the minimum possible number of such sets), then the best option will be to take sets. If , then such division is possible. If not, then it's impossible to divide ai balls into sets of x and x + 1 balls.

Time complexity of this solution is .

要么k个盒子要么放X个,k*x≤a[i],枚举x,k在1~根号a,直接枚举情况重复,去掉重复就是根号a了,枚举的情况看注释、、、

//orz

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
int a[505];
int n;
ll ans;
bool ff(int c) {
    int f = c - 1;
    if(f <= 0) return false;
    ll cnt = 0;
    for(int j = 0; j < n; ++j) {
        if(a[j] / f >= a[j] % f) {
            int x = a[j] / c;
            int y = a[j] % c;
            cnt += x;
            if(!y) continue;
            if(f - y <= x) {
                cnt++; continue;
            }
            return false;
        }
        else
            return false;
    }
    ans = min(ans, cnt);
    return true;
}
int main() {
    int mi = inf;
    scanf("%d", &n);
    ans = 0;
    int i, j;
    for(i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
        if(a[i] < mi) mi = a[i];
        ans += a[i];
    }
    int l = ceil(sqrt(mi)) + 1;
    for(i = 1; i <= l; ++i) {//枚举盒子数以及放的个数
        if(i != 1) ff(i);    // i   , i-1
        ff(mi / i);         // m/i , m/i-1
        ff(mi/i + 1);       // m/i+1 , m/i
    }
    printf("%I64d
", ans);
    return 0;
}

Codeforces Round #407(Div.2)

codeforces789 A. Anastasia and pebbles

官方题解: For every pebble type we can count the minimal number of pockets Anastasia need to collect all pebbles of this type. That's easy to notice that this number equals . So the answer for the problem is . Solution complexity is O(N).

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
int n, m, k, ans = 0;
int main(){
    scanf("%d%d", &n, &k);
    while(n--){
        scanf("%d", &m);
        ans += (m + k - 1) / k;
    }
    printf("%d
", (ans + 1) / 2 );
}

codeforces 789 B. Masha and geometric depression

官方题解:

We need to handle following cases in the solution:

  1. |b1| > l — answer is 0.
  2. b1 = 0 — if 0 is present in array a than answer is 0, else inf.
  3. q = 1 — if b1 is present in array a than answer is 0, else inf.
  4. q =  - 1 — if both b1 and  - b1 are present in array a than answer is 0, otherwise inf.
  5. q = 0 — if 0 isn't present in array a than answer is inf, else if b1 is present in a than answer is 0, else answer is 1.
  6. In all other cases we can simply iterate over all terms of progression b while their absolute value doesn't exceed l. For every term that is not present in a we simply increasing answer by 1. Obviously, the absolute value of every next element is bigger in at least 2 times than the absolute value of previous. That's why we'll need to check at most log l progression terms.

Solution complexity is O(M·logL) or O(M·logM + logL·logM).

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
ll b1, q, l, m;
map<int, int > mp;
int main(){
    scanf("%I64d%I64d%I64d%I64d", &b1, &q, &l, &m);
    int i, j, ans = 0, x;
    for(i = 0 ; i < m; ++i) {
        scanf("%d", &x);
        mp[x] = 1;
    }
    for(i = 0; i < 100; ++i) {
        if(abs(b1) > l) break;
        if(!mp[b1]) ans++;
        b1 *= q;
    }
    if(ans >= 50) puts("inf");//见下面第二个样例~
    else printf("%d
", ans);
}
/*
123 0 21 4
543453 -123 6 1424
inf

123 -1 2143435 5
-123 0 12 5 -11245
inf

11 0 228 5
-1 -17 1 5 -11245
inf
*/

codeforces 789 C. Functions again  【前缀和】

官方题解:

We can solve the problem for segments with odd and even l separately. Let's build arrays b (bi = |ai + 1 - ai|·( - 1)i) and c (ci = |ai + 1 - ai|·( - 1)i + 1). Obviously, that segment with the greatest sum in array b starts in some even index. In every segment starting in odd index we can move l one position right and make answer not-worse, because every element of odd index in b is non-positive. Also, sum of segment starting in even index of b equals to value of f on the same segment. Analogically for array c and odd starting indexes. So the answer equals to maximal of maximal sums of arrays b and c.

The segment with the greatest sum can be found with the two pointers method or using prefix sums. Such solution works with O(N) complexity.

//yy:求前缀和,求正的最大值和负的最小值,相减即为答案orz。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 1e5+5;
int n;
int main(){
    scanf("%d", &n);
    int x, y;
    ll ma = 0, mi = 0, d;
    ll s = 0;
    scanf("%d", &x);
    for(int i = 1; i < n; ++i) {
        scanf("%d", &y);
        d = abs(x - y);
        if(i % 2 == 0) d *= -1;
        s += d;
        if(s > ma) ma = s;
        if(s < mi) mi = s;
        x = y;
    }
    printf("%I64d
", ma - mi);
}

codeforces 789 D. Weird journey

官方题解:

We can consider the system of towns and roads as a graph, where edges correspond to roads and vertexes to cities.

Now, let's fix two edges, that will be visited once. All other edges we can split into two. Then, the good way in the old graph equivalents to any Euler path in the computed one. Widely known that Euler path exists in graph when and only when there are 0 or 2 vertexes with odd degree. Consider following cases of mutual placement of edges that will be visited once:

  • Regular(not loops) edges that are not adjacent — graph has four vertexes with odd degree, so Euler path doesn't exist.
  • Regular edges that are adjacent — graph has exactly two vertexes with odd degree, so Euler path exists. So, any pair of adjacent regular edges satisfies Igor.
  • One of the edges is a loop — graph hasn't any vertex with the odd degree(if another chosen edge is a loop too) or has two of them(if another chosen edge is regular). So, any pair in which at least one edge is a loop satisfies Igor.

So, we have to calculate the number of pairs of adjacent regular edges and add the answer for loops. For every vertex i we can calculate cnti — the number of regular edges incoming in it. General number of adjacent regular edges is . Also, we need to add the number of pairs with loops. Let's count loop — general number of loops in the graph. So we can add loop·(n - 1) to the answer. Now, we included pairs with two loops twice. That's why we need to subtract Cloop2 — the number of pairs with two loops.

Also, we need to check the graph to be connected by edges. If the graph is not connected then the answer is 0. We can do it using algorithms of DFS or BFS.

Complexity of the given solution if O(N + M).

 待补。。。。。。。

其他学习:2-sat问题

入门学习:http://blog.csdn.net/pi9nc/article/details/11849843

回忆:关键词:对称、环、极大强连通子图、拓扑排序、satisfiability

问对于一个合取范式,是否有一种输入使得他的输出是1,具体点就是类似这样的布尔表达式(x1 or x2 or x3)and(x3 or x4)and(not x1 or x5)对于所有的x是否有一种01取值,使得最后的结果是1。而2-sat问题就是每一个由or连接的子式都只包含两个变量,比如这样(x1 or x2) and (not x3 or x1)   

1)   hdu1814 Peaceful Commission 【2-SAT】[染色法]

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
#define lson rt*2
#define rson rt*2+1
#define CLR(a, b) memset((a), (b), sizeof((a)))
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int inf = 0x3f3f3f3f;
const int N = 20020;
const int M = 100010;
struct Edge {
    int to, next;
}edge[M];
int head[N], tot;
void init() {
    tot = 0;
    CLR(head, -1);
}
void addedge(int u, int v) {
    edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++;
}
bool vis[N];//染色标记,为true表示选择
int S[N], top;//
bool dfs(int u) {
    if(vis[u^1]) return false;
    if(vis[u]) return true;
    vis[u] = true;
    S[top++] = u;
    for(int i = head[u]; i != -1; i = edge[i].next)
        if(!dfs(edge[i].to))
            return false;
    return true;
}
bool Twosat(int n) {
    memset(vis, false, sizeof(vis));
    for(int i = 0; i < n; i += 2) {
        if(vis[i] || vis[i^1]) continue;
        top = 0;
        if(!dfs(i)) {
            while(top) vis[S[--top]] = false;
            if(!dfs(i^1)) return false;
        }
    }
    return true;
}
int main() {
    int n, m;
    int u, v;
    while(scanf("%d%d", &n, &m) == 2) {
        init();
        while(m--) {
            scanf("%d%d", &u, &v);
            u--; v--;
            addedge(u, v^1);
            addedge(v, u^1);
        }
        if(Twosat(2*n)) {
            for(int i = 0;i < 2*n; i++)
                if(vis[i])
                    printf("%d
", i+1);
        }
        else printf("NIE
");
    }
    return 0;
}

其他 待补。。。

原文地址:https://www.cnblogs.com/GraceSkyer/p/6654268.html