• HGOI 20190709


    第一天(前面咕了两天),210,没发挥好,凑合。

    1. 煎饼

    一共切横 (h) 加竖 (v) 刀,则一共分成 ((h+1)*(v+1))

    显然 (@) 总和 (sum)((h+1)*(v+1)) 的倍数,不是就不可能达到

    那么每块的大小就是 (dfrac{sum}{(h + 1) * (v+ 1)})

    这样就可以可以明确每行每列的刀的位置

    那么其他位置用二维前缀和check一下就行

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    #define enter cout << endl
    
    const int N = 110 ;
    
    int n, m, r, c, cntr, cntc, xgm, cnt ;
    int sum[N][N], a[N][N], row[N], col[N], psb[10 * N] ;
    string s ;
    
    int get(int X1, int Y1, int X2, int Y2) {
        return sum[X2][Y2] - sum[X1 - 1][Y2] - sum[X2][Y1 - 1] + sum[X1 - 1][Y1 - 1] ;  
    }
    
    void clear() {
        cnt = 0, xgm = 0 ;
        memset(sum, 0, sizeof(sum)) ;
    }
    
    signed main() {
        int t ; scanf("%d", &t) ;
        rep(rnd, 1, t) {
            clear() ;
            scanf("%d%d%d%d", &n, &m, &r, &c) ;
            rep(i, 1, n) {
                cin >> s ; 
                rep(j, 0, m - 1) a[i][j + 1] = (s[j] == '@') ? 1 : 0 ;
            }
            printf("Case #%d: ", rnd) ;
            rep(i, 1, n) 
            rep(j, 1, m)
            if (a[i][j] == 1) xgm++ ;
            rep(i, 1, n)
            rep(j, 1, m)
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j] ;
            if (!xgm) {
                puts("POSSIBLE") ;
                continue ;
            }
            if (xgm % (r + 1) != 0 || xgm % (c + 1) != 0) {
                puts("IMPOSSIBLE") ;
                continue ;
            }
            int sz = xgm / ((r + 1) * (c + 1)) ;
            int rowsz = xgm / (r + 1), colsz = xgm / (c + 1) ;
        //  cout << rowsz << " " << colsz << endl ;
            cntr = cntc = 0 ;
            int cur = 0 ;
            rep(i, 1, n) if (get(row[cur] + 1, 1, i, m) == rowsz) row[++cntr] = i, cur++ ;
            if (cur != r + 1) {
                puts("IMPOSSIBLE") ;
                continue ;
            }
            cur = 0 ;
            rep(j, 1, m) if (get(1, col[cur] + 1, n, j) == colsz) col[++cntc] = j, cur++ ;
            if (cur != c + 1) {
                puts("IMPOSSIBLE") ;
                continue ;
            }
            bool flg = true ;
            rep(i, 1, cntr)
            rep(j, 1, cntc)
            if (get(row[i - 1] + 1, col[j - 1] + 1, row[i], col[j]) != sz) {
                flg = false ;
                break ;
            }
            if (flg) puts("POSSIBLE") ;
            else puts("IMPOSSIBLE") ;
        }       
        return 0 ;
    }
    
    
    1. 机器人

    这题很简单,裸的二分,普及组难度

    二分答案,然后求出没个收银员的可手的甜甜圈数量,

    看前 (R) 大的和是否 >= (B)

    注意数量要与0取max

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    #define int long long
    
    const int N = 100010 ;
    
    int n, k, m, cnt ;
    int valid[N] ;
    
    struct node {
    	int m, s, p ; // Max = m, tim = s * n + p
    } a[N] ;
    
    bool cmp1(node a, node b) {
    	return a.s < b.s ;
    }
    
    bool cmp2(node a, node b) {
    	return a.p < b.p ;
    }
    
    bool cmp3(node a, node b) {
    	return a.s * min(a.m, b.m) + a.p < b.s * min(a.m, b.m) + b.p ; 
    }
    
    bool check(int tm) {
    	int rst = k, cnt = 0 ;
    	rep(i, 1, m) {
    		if (tm <= a[i].p) continue ;
    		valid[++cnt] = min(a[i].m, (tm - a[i].p) / a[i].s) ;
    	}
    	sort(valid + 1, valid + cnt + 1) ;
    	reverse(valid + 1, valid + cnt + 1) ;
    	rep(i, 1, min(n, cnt)) rst -= valid[i] ;
    	return rst <= 0 ; 
    }
    
    void clear() {
    	
    }
    
    signed main() {
    	freopen("robot.in", "r", stdin) ;
    	freopen("robot.out", "w", stdout) ; 
    	int t ; scanf("%lld", &t) ;
    	rep(rnd, 1, t) {
    		clear() ;
    		scanf("%lld%lld%lld", &n, &k, &m) ; // robot, sum, sell
    		rep(i, 1, m) scanf("%lld%lld%lld", &a[i].m, &a[i].s, &a[i].p) ;
    	//	sort(a + 1, a + m + 1, cmp1) ;
    		int l = 0, r = LONG_LONG_MAX / 2, mid ;
    	//	cout<<LONG_LONG_MAX<<endl ;
    		while (l < r) {
    			int mid = (l + r) >> 1ll ;
    			if (check(mid)) r = mid ;
    			else l = mid + 1 ;
    		}
    //		rep(i, max(0ll, l - 5), r + 5) 
    //		if (check(i)) {
    //			printf("%lld
    ", i) ;
    //			break ;
    //		} 
    		printf("Case #%d: %lld
    ", rnd, l) ;
    	}
    	
    	return 0 ;
    }
    
    
    1. 面包师

    这个题有点小难,考试时瞎搞骗分40

    其实就是个背包,只不过稍有变化

    每个面包要么不切,要么切开,

    切开对答案的贡献就是 ([2*min(x,y),2*sqrt{(x^2+y^2)}])

    所以问题就是取一些面包,然后使他们的贡献(区间)尽可能接近p

    设每一个面包的贡献是 ([low,up]), 令 (p-sum_{i=1}^n 2*(x+y)=k)

    首先可以观察到必定满足 (Σlow[i]<=p)

    会观察到 (Σlow[i]) 范围不叫小,大概是 (10^4)(10^5) 这么大

    那么可以考虑背包

    dp[i]表示 (Σlow=i)(Σup) 的最大值

    然后在(dp[0,min(Σlow,p)]) 的范围上找一个最大的,如果大于 (p) 就是 (p)

    如果没有就是它自己

    输出就行了

    还算基础(这你都做不对!)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 100010 ;
    
    int n, p, tot, Low ;
    int w[N], h[N], t[N] ;
    double delt[N], f[N] ;
    
    signed main() {
    	int T ;
    	scanf("%d", &T) ;
    	rep(rnd, 1, T) {
    		scanf("%d%d", &n, &p) ;
    		memset(t, 0, sizeof(t)) ;
    		Low = tot = 0 ;
    		rep(i, 1, n) {
    			scanf("%d%d", &w[i], &h[i]) ;
    			if (h[i] > w[i]) swap(w[i], h[i]) ;
    			tot += h[i] ; Low += h[i] + w[i] ;
    			delt[i] = sqrt(1.0 * w[i] * w[i] + 1.0 * h[i] * h[i]) - h[i] ;
    		}
    		rep(i, 0, tot) f[i] = 0 ;
    		t[0] = 1 ;
    		rep(i, 1, n)
    		per(j, tot, h[i])
    		if (t[j - h[i]])
    		f[j] = max(f[j], f[j - h[i]] + delt[i]), t[j] = 1 ;
    		double ans = 0 ;
    		rep(i, 0, tot) if (t[i] && Low * 2 + i * 2 <= p) ans = max(ans, min((double) p, f[i] * 2 + Low * 2 + i * 2)) ;
    		printf("Case #%d: %.6lf
    ", rnd, ans) ;
    	} 
    	return 0 ;
    }
    
    
  • 相关阅读:
    Netty大小端
    手写简单IOC
    Java线程
    mysql查询性能问题,加了order by速度慢了
    字节码增强技术探索
    Linux 添加定时任务
    一千行 MySQL 学习笔记
    深入浅出Shiro系列
    深入浅出SpringMVC系列~
    来聊一聊 Linux 常用命令 (第二篇)~
  • 原文地址:https://www.cnblogs.com/harryhqg/p/13285907.html
Copyright © 2020-2023  润新知