X Samara Regional Intercollegiate Programming Contest DIV2

http://codeforces.com/gym/101341

其实我觉得这份题很不错的,虽然是div2,但是感觉对我挺有帮助(我比较垃圾0.0),还没补完(做的时候一直蒙逼,要补很多题)先写一点点的题解,后面的以后补上。

A:

B:这题有一个bug就是,当你一个"happiness"都没有的时候,你交换哪一个?如果随机输出的话是有bug的,就是比如你交换1和2,(注意都是要不同的pos),那么我构造ahppiness,就错了,交换后出现就不行了。所以还要自己处理一下。我是找有没有两个相同的字母,有就交换他们,就相当于没变了,没有的话,就不会出现"pp"和"ss",怎么交换都是成立的。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 2e5 + 20;
char str[maxn];
char sub[] = "0happiness";
int lensub;
vector<int>pos[222];
void work() {
    scanf("%s", str + 1);
    int lenstr = strlen(str + 1);
    int beOne = 0, enOne = 0, beTwo = 0, enTwo = 0;
    char ch[22] = {0};
    for (int i = 1; i <= lenstr; ++i) {
        for (int j = 1; j <= 8; ++j) ch[j] = ch[j + 1];
        ch[9] = str[i];
        pos[str[i]].push_back(i);
        if (strcmp(ch + 1, sub + 1) == 0) {
            if (beOne == 0) {
                beOne = i - 8; enOne = i;
                continue;
            }
            if (beTwo == 0) {
                beTwo = i - 8; enTwo = i;
                continue;
            }
            printf("NO
");
            return;
        }
    }
//    printf("%d %d %d %d
", beOne, enOne, beTwo, enTwo);
    printf("YES
");
    if (!beOne && !beTwo) {
        for (int i = 'a'; i <= 'z'; ++i) {
            if (pos[i].size() >= 2) {
                printf("%d %d
", pos[i][0], pos[i][1]);
                return;
            }
        }
        printf("1 %d
", lenstr);
        return;
    }
    if (!beTwo) beTwo = 1;
    while (str[beTwo] == str[beOne]) beTwo++;
    printf("%d %d
", beOne, beTwo);
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    lensub = strlen(sub + 1);
    work();
    return 0;
}
View Code

C:推公式貌似有点难度,做的时候一直想着推公式,分类讨论太乱了。然后吃了个饭回来想到可以二分答案。二分答案val,判定条件是:首先对于每一种求,最多只能拿Min(val, a + c)个,然后判断其是否> n,

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
LL a, b, c, n, m;
bool check(LL val) {
    LL ra = min(val, a + c);
    LL rb = min(val, b + c);
    return ra <= n && rb <= m;
}
void work() {
    cin >> a >> b >> c >> n >> m;
    LL be = 0, en = a + b + c;
//    cout << check(3) << endl;
    while (be <= en) {
        LL mid = (be + en) >> 1;
        if (check(mid)) be = mid + 1;
        else en = mid - 1;
    }
    cout << en << endl;
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
View Code

D:签到题,对于一个数,可以向左跳或者向右跳,相当于可以加,可以减。回顾ax + by = c是否有整数解,只需要gcd(a, b) | c

这是扩展欧几里德的内容,现在扩展到n个,一样的gcd即可。(比赛的时候还卡了这题,哭)

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
map<int, bool>vis, ans;
const int maxn = 200000 + 20;
int a[maxn], n;
const int low = -1e9, high = 1e9;
int x;

void work() {
    scanf("%d%d", &n, &x);
    scanf("%d", a + 1);
    int gg = a[1];
    for (int i = 2; i <= n; ++i) {
        scanf("%d", a + i);
        gg = __gcd(gg, a[i]);
    }
    if (x % gg == 0) printf("YES
");
    else printf("NO
");
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
View Code

E:这题我写得很复杂,也没看懂别人如何贪心,我是直接化公式,然后暴力segment tree维护。思路是,他从t1开始,首先把它左边的点都暴力走过去,因为没有其他方法了,然后,就是在[t1, t2]这段路上,选一个点(可能不选),走过去,然后走回t1传送去t2,然后从t2走去左边剩下的点,再走回来。一共花费的时间是,假如[t1, t2]这里有两个点pos[1], pos[2],那么花费的时间是,(pos[1] - t1) * 2 + (t2 - pos[2]) * 2 = 2 * (t2 - t1) + 2 * (pos[1] - pos[2]),所以应该选一个pos[i] - pos[i + 1]最小的去走,线段树维护。很复杂啦写的,

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 200000 + 20;
#define root 1, m, 1
#define lson L, mid, cur << 1
#define rson mid + 1, R, cur << 1 | 1
LL a[maxn], b[maxn];
LL dis[maxn];
LL mi[maxn << 2];
void pushUp(int cur) {
    mi[cur] = min(mi[cur << 1], mi[cur << 1 | 1]);
}
void build(int L, int R, int cur) {
    if (L == R) {
        mi[cur] = dis[L];
        return;
    }
    int mid = (L + R) >> 1;
    build(lson);
    build(rson);
    pushUp(cur);
}
LL ask(int be, int en, int L, int R, int cur) {
    if (be > en) return inf + inf;
    if (L >= be && R <= en) {
        return mi[cur];
    }
    int mid = (L + R) >> 1;
    LL ans = inf + inf;
    if (be <= mid) {
        ans = ask(be, en, lson);
    }
    if (en > mid) {
        ans = min(ans, ask(be, en, rson));
    }
    return ans;
}
void work() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) cin >> a[i];
    for (int i = 1; i <= m; ++i) {
        cin >> b[i];
        if (i > 1) {
            dis[i - 1] = b[i - 1] - b[i];
        }
    }
    dis[m] = inf + inf;
    build(root);
    a[n + 1] = inf;
    LL sumTime = 0;
    int pb = 1, pa = 1;
    if (b[pb] <=  a[1]) {
        sumTime += 2 * (a[1] - b[pb]);
    }
    while (pb <= m && b[pb] <= a[1]) pb++;
    while (pb <= m) {
        if (pa == n) {
            sumTime += (b[m] - a[pa]) * 2;
            break;
        }
        if (a[pa + 1] <= b[pb]) {
            pa++;
            continue;
        }
        LL res1 = a[pa + 1] - a[pa];
        res1 = min(res1, (a[pa + 1] - b[pb]) * 2);
        if (b[pb + 1] <= a[pa + 1]) {
            res1 = min(res1, (b[pb] - a[pa]) * 2 + (a[pa + 1] - b[pb + 1]) * 2);
        } else res1 = min(res1, (b[pb] - a[pa]) * 2);
        int pos1 = lower_bound(b + 1, b + 1 + m, a[pa]) - b;
        int pos2 = upper_bound(b + 1, b + 1 + m, a[pa + 1]) - b;
        res1 = min(res1, (b[pos2 - 1] - a[pa]) * 2);
        pos2 -= 2;
//        cout << dis[2] << endl;
//        cout << ask(pos1, pos2, root) << endl;
        LL res3 = 2 * ask(pos1, pos2, root) + 2 * (a[pa + 1] - a[pa]);
//        cout << res3 << endl;
        sumTime += min(res1, res3);
        pa++;
        while (pb <= m && b[pb] <= a[pa]) pb++;
    }
    cout << sumTime << endl;
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
View Code

F:

G:倒序模拟,一开始找1所在的位置pos, 设1喜欢的人是y[pos],然后就相当于找y[pos]那个人的名字,也是倒序模拟,直到找不到了,就直接输出那个人的名字就ok

H:能证明的是,首先找到一个最大的数字val,在row,col中,这个数字是必定删除的,然后试试删除row,或者删除col,4种情况试一试就好。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
typedef pair<int, int> pii;
const int maxn = 1e3 + 20;
int a[maxn][maxn];
int n, m;
pii findMax(int delRow, int delCol) {
    int mx = -1, row = -1, col = -1;
    for (int i = 1; i <= n; ++i) {
        if (i == delRow) continue;
        for (int j = 1; j <= m; ++j) {
            if (j == delCol) continue;
            if (mx < a[i][j]) {
                mx = a[i][j];
                row = i;
                col = j;
            }
        }
    }
    return make_pair(row, col);
}
vector< pair<pii, int> >vc;
int ansMx = inf;
void dfs(int row, int col, int delRow, int delCol) {
    pii res = findMax(delRow, delCol);
    if (!row && !col) {
        vc.push_back(make_pair(make_pair(delRow, delCol), a[res.first][res.second]));
        if (ansMx > a[res.first][res.second]) {
            ansMx = a[res.first][res.second];
        }
        return;
    }
    if (row) {
        dfs(row - 1, col, res.first, delCol);
    }
    if (col) {
        dfs(row, col - 1, delRow, res.second);
    }
}
void work() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            cin >> a[i][j];
        }
    }
    dfs(1, 1, 0, 0);
    for (int i = 0; i < vc.size(); ++i) {
        if (vc[i].second == ansMx) {
            cout << vc[i].first.first << " " << vc[i].first.second << endl;
            return;
        }
    }
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    IOS;
    work();
    return 0;
}
View Code

I:这是一题神奇的题,其实这个东西我应该算学过,但是它换去矩阵了,所以就转不过来,思路是随机生成一个矩阵[1 X n]的矩阵,那么有rand * a * b = rand * c,这些复杂度才O(n^2),多随机几个,概率就满足了。这有点像那些米勒测试啊。

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = 1e3 + 2;
struct Matrix {
    int a[maxn][maxn];
    int row;
    int col;
    bool operator != (struct Matrix& rhs) const {
        for (int i = 1; i <= col; ++i) {
            if (a[1][i] != rhs.a[1][i]) return true;
        }
        return false;
    }
}ans[4], c, cmp;
struct Matrix matrix_mul(struct Matrix a, struct Matrix b, int MOD) { //求解矩阵a*b%MOD
//    struct Matrix c = {0};  //这个要多次用到,栈分配问题,maxn不能开太大,
    //LL的时候更加是,空间是maxn*maxn的,这样时间用得很多,4和5相差300ms
    c.row = a.row; //行等于第一个矩阵的行
    c.col = b.col; //列等于第二个矩阵的列
    for (int i = 1; i <= c.row; ++i) for (int j = 1; j <= c.col; ++j) c.a[i][j] = 0;
    for (register int i = 1; i <= a.row; ++i) {
        for (register int k = 1; k <= a.col; ++k) {
            if (a.a[i][k]) { //应付稀疏矩阵,0就不用枚举下面了
                for (register int j = 1; j <= b.col; ++j) {
                    c.a[i][j] = (c.a[i][j] + 1LL * a.a[i][k] * b.a[k][j]) % MOD;
                }
            }
        }
    }
    return c;
}
void work() {
    srand((time(NULL)));
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= 3; ++i) {
        ans[i].row = ans[i].col = n;
        for (int j = 1; j <= n; ++j) {
            for (int k = 1; k <= n; ++k) {
                scanf("%d", &ans[i].a[j][k]);
            }
        }
    }
    cmp.row = 1, cmp.col = n;
//    cout << RAND_MAX << endl;
    for (int i = 1; i <= 25; ++i) {
        int upDate = rand();
        for (int k = 1; k <= n; ++k) {
            cmp.a[1][k] = rand() % 13131 + upDate;
        }
        Matrix res1 = matrix_mul(cmp, ans[1], 1e9 + 7);
        res1 = matrix_mul(res1, ans[2], 1e9 + 7);
        Matrix res2 = matrix_mul(cmp, ans[3], 1e9 + 7);
        if (res1 != res2) {
            printf("NO
");
            return;
        }
    }
    printf("YES
");
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    work();
    return 0;
}
666

J:

K:

L:

M:签到题,模拟即可。一个人优先杀最后那个。

原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6978062.html