Codeforces Round #506 (Div. 3)

A. Many Equal Substrings

题解:数据比较小,可以暴力。当数据有1e5时,可以利用kmp的nxt数组得到最长的相同的前缀和后缀。

B. Creating the Contest

ps:~

C. Maximal Intersection

题解:n条线段的相交部分一定是(Lmax,Rmin),那么我们可以暴力删除每一条线段,然后查询最大的左端点和最小的右端点,更新答案。multiset可以维护重复的元素!!!!

const int N = 300005;

int n;
int l[N], r[N];

multiset<int, greater<int> > L;
multiset<int> R;

int main()
{
    sc(n);
    Rep(i, 1, n) {
        sc(l[i]), sc(r[i]);
        L.insert(l[i]);
        R.insert(r[i]);
    }
    int ans = 0;
    Rep(i, 1, n) {
        L.erase(L.find(l[i]));
        R.erase(R.find(r[i]));
        ans = max(ans, *R.begin() - *L.begin());
        L.insert(l[i]);
        R.insert(r[i]);
    }
    pr(ans);
    return 0;
}

D. Concatenated Multiples

题解:正整数a,b,ab % k = 0 等价于 a * size(b) % k + b % k = k,所以可以枚举b的长度,再用map标记一下。

ps:交换红色部分的循环顺序,就会T。(假)说明:尽量在同一个map里连续操作,避免在不同map里跳着查询。至于真正的原因,I DON'T KNOW  !!!

inline void upd(int &x, int y) { x < y && (x = y); }

const int N = 200005;

LL n, k;
LL a[N], b[N], c[N];

unordered_map<int, int> sp[12];

int get(LL x) {
    int cnt = 0;
    while(x) cnt++, x /= 10;
    return cnt;
}

int main()
{
    IOS;
    
    cin >> n >> k;
    Rep(i, 1, n) {
        cin >> a[i];
        b[i] = get(a[i]);
        c[i] = a[i] % k;
        sp[b[i]][c[i]]++;
    }

    LL cnt = 0;
    LL tt, tp;

    LL p[11];
    p[1]= 10;
    Rep(i, 2, 10) p[i] = p[i - 1] * 10 % k;

    Rep(j, 1, 10) Rep(i, 1, n) {

        tp = (k - (p[j] % k * a[i]) % k);
        if (tp == k) tp = 0;

        tt = sp[j][tp];

        if (!tt) continue;
        cnt += tt;

        if ((b[i] == j) && (tp == c[i])) cnt--;
    }

    cout << cnt << endl;
    return 0;
}

 E. Tree with Small Distances

ps:贪心,从底向上,标记节点的父亲比标记节点更优

const int N = 2e5;

int n, pa[N];
bool use[N];

vector<int> G[N], arr;

void DFS(int u = 0, int d = 0, int p = 0) {
    pa[u] = p;
    for (auto v : G[u]) if (v != p) DFS(v, d + 1, u);
    if (d > 2) arr.pb(u);
}

int main() {

    cin >> n;
    rep(i, 1, n){
        int u, v;
        cin >> u >> v;
        u--, v--;
        G[u].pb(v);
        G[v].pb(u);
    }

    DFS();

    int ans = 0;
    for (auto u : arr) if (!use[u]) {
        ans++;
        for (auto v : G[pa[u]]) use[v] = 1;
        use[pa[u]] = 1;
    }

    cout << ans << endl;
    return 0;
}

 F. Multicolored Markers

题解:大矩形的形状容易确定,重点在于检查其中一种颜色在当前矩形中是否能填成矩形,枚举矩形的短边,二分检查颜色a,颜色b能否组成矩形。

inline void upd(int &x, int y) { x < y && (x = y); }

const int N = 100000005;

LL a, b;

vector<LL> s, sa, sb;

void Inite() {

    s.clear();
    sa.clear();
    sb.clear();

    LL x = a + b;
    Rep(i, 1, (int)sqrt(x)) if (x % i == 0) s.pb(i);

    x = a;
    Rep(i, 1, (int)sqrt(x)) if (x % i == 0) sa.pb(i);

    x = b;
    Rep(i, 1, (int)sqrt(x)) if (x % i == 0) sb.pb(i);
}

void Solve() {
    LL ans = INF64;
    for(auto x : s) {

        bool flag = 0;

        int pos1 = lower_bound(Range(sa), x) - sa.begin();
        int t = (sa[pos1] == x ? x : sa[pos1 - 1]);

        if (a / t <= (a + b) / x) flag = 1;

        int pos2 = lower_bound(Range(sb), x) - sb.begin();
        int o = (sb[pos2] == x ? x : sb[pos2 - 1]);

        if (b / o <= (a + b) / x) flag = 1;

        LL tp = 2 * ((a + b) / x + x);
        if (flag && tp < ans) ans = tp;
    }
    cout << ans << endl;
}

int main()
{
    cin >> a >> b;
    Inite();
    Solve();
    return 0;
}

 ps:有些代码写得真的很优秀

LL a, b, c;
set<LL> s;    // 矩形的长(长 >= 宽)的集合

int main()
{
    cin >> a >> b;
    c = a + b;
    LL ans = INF64;
    for (LL i = 1; i * i <= c; ++i) {
        if (a % i == 0 && i * i <= a) s.insert(a / i);
        if (b % i == 0 && i * i <= b) s.insert(b / i);
        if (c % i == 0 && c / i >= *s.begin()) ans = min(ans, 2 * (c / i + i));     // 保证了 a矩形的长 和 b矩形的长 都小于等于 c矩形的长   
} cout
<< ans << endl; return 0; }

 

posted @ 2018-08-25 19:46  天之道,利而不害  阅读(241)  评论(0编辑  收藏  举报