zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

    未完待续~

    编译人生,运行世界!
  • 相关阅读:
    11g 配置 dgmgrl 以及报错 DataGuard ORA-00313,
    java三种匿名的方式开启线程
    java 四种方式实现字符流文件的拷贝对比
    java中过滤查询文件
    通过Java实现斗地主
    java中Map的entrySet 和keySet的使用
    python3列表推导式和生成器。
    python的特殊方法总结
    python3 定义向量运算
    python3模拟扑克牌
  • 原文地址:https://www.cnblogs.com/Running-Time/p/4780632.html
Copyright © 2011-2022 走看看