Codeforces Round #311 (Div. 2)

水 A - Ilya and Diplomas

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

int a[4];

int main(void)  {
    int n;  cin >> n;
    int mn1, mx1, mn2, mx2, mn3, mx3;
    cin >> mn1 >> mx1;
    cin >> mn2 >> mx2;
    cin >> mn3 >> mx3;
    a[3] = mn3; a[2] = mn2;
    int res = n - a[2] - a[3];
    if (res <= mx1) a[1] = res;
    else    {
        a[1] = mx1; res -= a[1];
        if (a[2] + res <= mx2)  a[2] += res;
        else    {
            a[2] = mx2; a[3] += (res - (a[2] - mn2));
        }
    }

    cout << a[1] << " " << a[2] << " " << a[3] << endl;

    return 0;
}

贪心 || 二分 B - Pasha and Tea

题意:有n个girl和n个boy喝茶,茶杯的容量不等,boy喝的是girl的两倍且boy喝的一样多,girl喝的一样多,问主人最多能倒出多少水

分析:第一反应是用二分搜索girl喝的茶容量,可惜写搓了,mid应该和茶量最小的girl以及boy去比较。看过的代码竟然99%都是贪心,晕~

代码(二分):

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;

const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const double EPS = 1e-9;
int a[N*2];

int main(void)  {
    int n;  int w;   scanf ("%d%d", &n, &w);
    n *= 2;
    for (int i=1; i<=n; ++i)  {
        scanf ("%d", &a[i]);
    }
    sort (a+1, a+1+n);
    double l = 0.0, r = w;
    double mid = 0.0, ans = 0.0;
    for (int i=1; i<=100; ++i)   {
        mid = (l + r) / 2.0;
        if (mid >= 0 && mid <= a[1] && mid * 2 <= a[n/2+1] && mid * 1.5 * n <= w)    {
            l = mid;
            ans = mid * 1.5 * n;
        }
        else    r = mid;
    }
    printf ("%.6f
", ans);

    return 0;
}

代码(贪心):

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;

const int N = 1e5 + 10;
int a[N*2];

int main(void)  {
    int n, w;   scanf ("%d%d", &n, &w);
    n *= 2;
    for (int i=1; i<=n; ++i)    scanf ("%d", &a[i]);
    sort (a+1, a+1+n);
    double ans = min (a[1] * 1.0, a[n/2+1] / 2.0);
    ans = min (ans * 3 * n / 2.0, w * 1.0);
    printf ("%.6f
", ans);

    return 0;
}

构造+贪心:C - Arthur and Table

题意:简单说就是拿掉一些凳脚,使得剩下的最长的凳脚的个数比一半还多,每条凳子有拿走的费用,问最小费用是多少。

分析:先按照凳长排序,从最大的开始枚举,相同长度的跳过,那么统计还需要拿掉几条凳脚,优先拿费用小的,怎么找呢?这题很人性的将费用范围定在200内,直接暴力找啊!

收获:算不上收获,这道题不需要什么算法,脑子清晰地实现代码,构造题要思维严谨,逻辑清楚

代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
struct Leg	{
	int l, cnt, d;
	bool operator < (const Leg &r) const {
		return l < r.l;
	}
}leg[N];
int c[222];

int main(void)	{
	int n;	scanf ("%d", &n);
	for (int i=1; i<=n; ++i)	{
		scanf ("%d", &leg[i].l);
	}
	memset (c, 0, sizeof (c));
	int tot = 0;
	for (int i=1; i<=n; ++i)	{
		scanf ("%d", &leg[i].d);
		tot += leg[i].d;	c[leg[i].d]++;
	}
	sort (leg+1, leg+1+n);
	int i = n, ans = INF, sum = 0;
	while (i >= 1)	{
		int l, r = i;
		while (i > 1 && leg[i].l == leg[i-1].l)	{
			c[leg[i].d]--;	i--;
		}
		c[leg[i].d]--;	l = i;
		int num = r - l + 1;
		if (num * 2 -1 >= r)	ans = min (ans, sum);
		else if (num == 1)	ans = min (ans, tot - leg[i].d);
		else	{
			int res = r - (num * 2 - 1);
			int cost = 0;
			for (int j=0; j<=200 && res > 0; ++j)	{
				if (c[j])	{
					int t = min (res, c[j]);
					res -= t;
					cost += t * j;
				}
			}
			ans = min (ans, sum + cost);
		}
		i--;
		for (int j=l; j<=r; ++j)	sum += leg[j].d;
	}

	printf ("%d
", ans);

	return 0;
}

  

UPD:

字典树+区间DP/Hash+DFS E - Ann and Half-Palindrome

题意:一个长度n的字符串(n<=5000),仅含有a和b,定义半回文串:满足当i是奇数位置,且str[i]=str[n-1-i](i<=(n+1)/2)的串,求所有子串按照字典序后第k个字串。

思路:没注意到复杂度是可以接受的。首先区间DP判断子串[i,j]是否为半回文串,然后将所有子串插入字典树上,插入的过程中标记是半回文串的点,然后DFS中序遍历,找第k个。

#include <bits/stdc++.h>

const int N = 5e3 + 5;
const int NODE = N * (N+1) / 2;

int ch[NODE][2];
int val[NODE];
int sz;

char str[N];
bool dp[N][N];
int n, k;

void trie_init() {
    //memset (ch[0], 0, sizeof (ch[0]));
    //val[0] = 0;
    sz = 1;
}

void trie_insert(char *s, int start) {
    int u = 0, c;
    for (int i=start; i<n; ++i) {
        c = s[i]-'a';
        if (!ch[u][c]) {
            memset (ch[sz], 0, sizeof (ch[sz]));
            val[sz] = 0;
            ch[u][c] = sz++;
        }
        u = ch[u][c];
        if (dp[start][i]) val[u]++;
    }
}

char path[N];
int m;

bool trie_DFS(int u) {
    k -= val[u];
    if (k <= 0) return true;  //printf, exit (0);
    for (int i=0; i<2; ++i) {
        if (ch[u][i]) {
            path[m++] = 'a' + i; path[m] = '';
            if (trie_DFS (ch[u][i])) return true;
            path[--m] = '';
        }
    }
    return false;
}

void solve(char *s) {
    n = strlen (s);
    for (int i=0; i<n; ++i) {
        for (int j=i; j>=0; --j) {
            if (i - j <= 3) {
                dp[j][i] = (s[j] == s[i]);
            } else {
                dp[j][i] = (s[j] == s[i]) && dp[j+2][i-2];
            }
        }
    }

    trie_init ();
    for (int i=0; i<n; ++i) {
        trie_insert (s, i);
    }
    m = 0;
    trie_DFS (0);
    printf ("%s
", path);
}

int main() {
    scanf ("%s%d", str, &k);
    solve (str);
    return 0;
}

再附上铭神的hash+指针字典树代码

#include <bits/stdc++.h>
using ull = unsigned long long;

const int N = 5e3 + 5;
const ull base = 233;
ull base_pow[N];
ull lhash[N], rhash[N];
char str[N];
int n, k;

ull get_hash(ull *hash, int p, int len) {
    if (len & 1) len++;
    return hash[p] - hash[p+len] * base_pow[len/2];
}

struct Node {
    Node *go[2];
    int cnt;
};

Node pool[N*N], *alloc, *root;

void insert(int p) {
    Node *u = root;
    for (int i=0; p+i<n; ++i) {
        int c = str[p+i] - 'a';
        if (u->go[c] == NULL) {
            u->go[c] = alloc++;
        }
        u = u->go[c];
        int len = i + 1;
        if (get_hash (lhash, p, len+1>>1) == get_hash (rhash, n-1-(p+i), len+1>>1)) {
            u->cnt++;
        }
    }
}

std::vector<int> path;

bool DFS(Node *u) {
    if (u == NULL) return false;
    k -= u->cnt;
    if (k <= 0) return true;
    path.push_back(0);
    if (DFS(u->go[0])) return true;
    path.back() = 1;
    if (DFS(u->go[1])) return true;
    path.pop_back();
    return false;
}

int main() {
    scanf ("%s%d", str, &k);
    n = strlen (str);
    base_pow[0] = 1;
    for (int i=1; i<N; ++i) {
        base_pow[i] = base_pow[i-1] * base;
    }
    for (int i=n-1; i>=0; --i) {
        lhash[i] = lhash[i+2] * base + str[i];
        rhash[i] = rhash[i+2] * base + str[n-1-i];
    }
    alloc = pool;
    root = alloc++;
    for (int i=0; i<n; ++i) {
        insert (i);
    }
    DFS (root);
    for (auto t: path) {
        putchar ('a' + t);
    }
    puts ("");
    return 0;
}

  

未完待续~

编译人生,运行世界!
原文地址:https://www.cnblogs.com/Running-Time/p/4780632.html