• 牛客寒假算法基础集训营6 解题报告


    前言

    离ak最近的1场qwq

    写了9题,再给我5min就能ak的

    混了个rk20多qwq

    怎么天天出原题啊我做过的都有3道了

    A

    做法 : 小学奥数

    小学奥数题吧...
    只要你智商在线,人脑里模拟一下不就行了
    显然也就那么几种情况。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define N 10000100
    
    ll n, m;
    
    int main() {
        scanf("%lld%lld", &n, &m);
        if(n > m * 9 || n < m * 6) return puts("jgzjgzjgz"), 0;
        ll c = n - m * 6;
        if(c > m) puts("0");
        else printf("%lld
    ", m - c);
        return 0;
    }
    

    B

    做法:暴力/二分

    一眼秒是二分。
    具体做法是二分天数,然后等差数列求和判断。
    但是写挂了不知道是溢出了还是什么。赛后交了是90分。
    最后一个大爷告诉我暴力能过...
    怪不得是全场通过最多

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod = 1e9 + 7;
    #define N 5000050
      
    ll n, m, d, x;
      
    bool check(ll x) {
        __int128 s = (__int128)(x * d + n + n) * x / 2;
        return s >= (__int128)m;
    }
      
    int main() {
        scanf("%lld%lld%lld%lld", &n, &m, &d, &x);
        ll ans = 0, res = 0;
        while(res < m) {
            res += n;
            n += d;
            ans++;
        }
        printf("%lld
    ", ans);
    }
    

    C

    做法:贪心

    因为没啥特殊性质,显然直接按涂上去的价值排序就好,然后取前n大的价值即可
    是个sb题

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define N 10000100
    int n, m;
    struct Node {
        int a, b;
    } a[N];
     
    bool operator < (Node a, Node b) {
        return a.b > b.b;
    }
     
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; ++i) scanf("%d", &a[i].a);  for(int i = 1; i <= m; ++i) scanf("%d", &a[i].b);
        sort(a + 1, a + m + 1);
        ll ans = 0;
        for(int i = 1; i <= m; ++i) {
            if(n >= a[i].a) {
                ans += 1ll * a[i].a * a[i].b;
                n -= a[i].a;
            } else {
    //            if(!n) break;
                ans += 1ll * a[i].b * n;
                break;
            }
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    D

    做法:贪心

    之前做过类似的题,貌似是洛谷月赛。
    绝对值小于等于1,很麻烦,所以不如钦定每一堆只要能拿就一定拿完,如果有一个要凑的就从右边拿。
    这个正确性挺显然的吧,如果不是很理解可以把样例画出来自己看看

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod = 1e9 + 7;
    #define N 5000050
     
    int n;
    ll a[N];
    
    int main() {
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
        ll ans = 0;
        for(int i = 1; i <= n; ++i) {
            ans += a[i] / 2;
            if(a[i] % 2 == 0) continue;
            if(a[i + 1] == 0) continue;
            ans++; a[i + 1]--;
        }
        printf("%lld
    ", ans);
    }
    

    E

    做法:二维前缀和

    sb题啊。。。
    一开始以为是个神仙题。我看错了题意以为d是每次给定的,结果是先给的。。。
    那么就和NOIP2016组合数问题基本一样了
    怎么天天出原题啊
    预处理(sum[i][j])表示前([i,j])个格子,满足值大于等于d的有多少个。
    那么按二维前缀和的思路容斥一下就好。如果不了解二维前缀和的看一下下面这个式子也就懂了
    (sum[l2][r2] + sum[l1 - 1][r1 - 1] - sum[l1 - 1][r2] - sum[l2][r1 - 1])
    实在不行再画个图?那图网上找找就好,烂大街的图
    至于(n*m<1e6)开个vector就好
    据说卡空间,不过我是没给卡到

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <cmath>
    #include <stack>
    #include <deque>
    #include <map>
    #include <set>
    
    #define ll long long
    #define inf 0x3f3f3f3f
    #define il inline
    
    namespace io {
    
        #define in(a) a=read()
        #define out(a) write(a)
        #define outn(a) out(a),putchar('
    ')
    
        #define I_int ll
        inline I_int read() {
            I_int x = 0 , f = 1 ; char c = getchar() ;
            while( c < '0' || c > '9' ) { if( c == '-' ) f = -1 ; c = getchar() ; }
            while( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; }
            return x * f ;
        }
        char F[ 200 ] ;
        inline void write( I_int x ) {
            if( x == 0 ) { putchar( '0' ) ; return ; }
            I_int tmp = x > 0 ? x : -x ;
            if( x < 0 ) putchar( '-' ) ;
            int cnt = 0 ;
            while( tmp > 0 ) {
                F[ cnt ++ ] = tmp % 10 + '0' ;
                tmp /= 10 ;
            }
            while( cnt > 0 ) putchar( F[ -- cnt ] ) ;
        }
        #undef I_int
    
    }
    using namespace io ;
    
    using namespace std ;
    
    #define N 1000100
    
    int n, m, d;
    vector<int>sum[N];
    
    int main() {
    	n = read(), m = read(), d = read();
    	for(int i = 1; i <= n; ++i) sum[i].push_back(0); for(int i = 0; i <= m; ++i) sum[0].push_back(0);
    	for(int i = 1; i <= n; ++i) {
    		for(int j = 1; j <= m; ++j) {
    			int x = read();
    			x < d ? sum[i].push_back(0) : sum[i].push_back(1);
    		}
    	} 
    	for(int i = 1; i <= n; ++i) {
    		for(int j = 1; j <= m; ++j) {
    			sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
    		}
    	}
    	int Q = read();
    	while(Q--) {
    		int l1 = read(), r1 = read(), l2 = read(), r2 = read();
    		int ans = sum[l2][r2] + sum[l1 - 1][r1 - 1] - sum[l1 - 1][r2] - sum[l2][r1 - 1];
    		printf("%d
    ", ans);
    	}
    	return 0;
    }
    

    F

    做法:搜索+构造

    唯一的难题。
    大致做法是宽搜一下,因为其实合法的构造方案很少。
    结束了就弃了没写,这题具体做法还是看看官方题解吧。。。

    G

    做法:按位贪心

    挺显然的一道题,3min秒了,然后因为上界搞错调了要1h。
    或的规则是有1则1,那么考虑每一位,如果(b-a)(即a到b变换了的位数,这中间肯定有1)比这一位大,那么显然就会有一个1跟他或一下,那么这一位就固定为1了
    上界要枚举到62...我上界试了31,32,63都挂了...最后62就过了,有毒

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod = 1e9 + 7;
    #define N 5000050
      
    ll a, b;
    
    int main() {
        while(~scanf("%lld%lld", &a, &b)) {
            ll ans = b | a;
            for(ll k = 63; k >= 0; k--) {
                if((ll)(1ll << (k)) <= (b - a)) ans |= (1ll << (k));
            }
            printf("%lld
    ", ans);
        }
    }
    /*
    枚举每一位
    对于一位k,如果(a-b)>=(1<<k),那么这一位就可以|1
    */
    

    H

    做法:暴力枚举+线段树优化

    这题做了好久...做完这题,F时间就不够了...
    一开始没啥思路,然后蔡队在牛客群上说了:“H有啥难的,暴力枚举啊”
    orz。
    然后往这方面想了想就想出来了。
    显然比较麻烦的就是这个全体右移k位。
    如果我们知道了一共要右移x次,那么其实每头猪的最小代价其实是确定了的,就是(min(a_i,min(a_{i-x}...a_{i-1})+x))(这是因为我们可以安排放入这头猪的时间,比如我们要取(i-2)这个地方的代价来填(i)这个位置,那么我们在剩下两次右移次数的时候放入(i-2)这个地方就好了。如果要用原来的价值,那么全部右移完后再放进去就好)
    所以现在就明朗了。
    枚举右移次数k,对于每个k算出最小代价,使用数据结构求区间最小值就可以了。
    我一开始st表写挂了。。。爆了4发。最后用了线段树过了。
    至于n右移了会到1的,可以分类讨论一下,也可以直接断环成链。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define N 100010
    const ll inf = 1e18;
    #define int long long
    
    int n, x;
    int a[N];
    
    struct tree{
        int l,r,mn;
    }t[N<<2];
    #define mid ((l + r) >> 1)
    #define lc (rt << 1)
    #define rc (rt << 1 | 1)
    void pushup(int rt) {
    	t[rt].mn = min(t[lc].mn, t[rc].mn);
    }
    void build(int l, int r, int rt) {
    	t[rt].l = l; t[rt].r = r;
    	if(l == r) {
    		t[rt].mn = a[l];
    		return;
    	}
    	build(l, mid, lc); build(mid + 1, r, rc); pushup(rt);
    }
    #define l t[rt].l
    #define r t[rt].r
    int query(int L, int R, int rt) {
    	if(L <= l && r <= R) {
    		return t[rt].mn;
    	}
    	int ans = inf;
    	if(L <= mid) ans = min(ans, query(L, R, lc));
    	if(R > mid) ans = min(ans, query(L, R, rc));
    	return ans;
    }
    #undef l
    #undef r
    #undef mid
    #undef lc
    #undef rc
    
    signed main() {
        scanf("%lld%lld", &n, &x);
        for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
        build(1, n, 1);
        ll ans = 1e18;
        for(int k = 0; k <= n; ++k) {
        	ll sum = k * x;
        	for(int i = 1; i <= n; ++i) {
        		if(i - k < 1) sum += min(query(1, i, 1), query(n - k + i, n, 1));
        		else sum += query(i - k, i, 1);
    		}
    		ans = min(ans, sum);
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    

    I

    栈(括号序列)

    本质上就是个括号序列
    因为注意到每次最多只能+10分,最少+5分(+0我们肯定不会去选他)。
    而且每个得分需要的次数是一样的。于是我们有一个贪心的做法。每次把当前数和栈顶比较,如果可以匹配则弹出并将答案+10,如果不行就扔进栈里。
    最后把栈里的两两弹出并+5即可
    抽象一下,就是个括号序列匹配而已

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod = 1e9 + 7;
    #define N 1000010
      
    char s[N];
    int st[N];
    
    int main() {
        scanf("%s", s + 1);
        int ans = 0, n = strlen(s + 1), top = 0;
        for(int i = 1; i <= n; ++i) {
        	if(!top) {
        		st[++top] = s[i] - '0';
        		continue;
    		}
    		if(s[i] - '0' == st[top]) {
    			top--;
    			ans += 10;
    		} else {
    			st[++top] = s[i] - '0';
    		}
    	}
    	while(top) {
    		top -= 2;
    		ans += 5;
    	}
    	printf("%d
    ", ans);
    }
    

    J

    做法:搜索

    直接搜就行了。。。
    因为是原题所以我就懒得写了,我拿了我以前写过的那题的代码交了,用的spfa。
    原题是CF1064D
    http://codeforces.com/contest/1064/problem/D
    正好我当时打过。。。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    #define ll long long
    #define debug printf("233
    ")
    #define inf 0x3f3f3f3f 
    #define il inline 
    #define in1(a) read(a)
    #define in2(a,b) in1(a),in1(b)
    #define in3(a,b,c) in2(a,b),in1(c)
    #define in4(a,b,c,d) in2(a,b),in2(c,d)
    
    inline void read( int &x ){
        x = 0 ; int f = 1 ; char c = getchar() ;
        while( c < '0' || c > '9' ) {
            if( c == '-' ) f = -1 ;
            c = getchar() ;
        }
        while( c >= '0' && c <= '9' ) {
            x = (x << 1) + (x << 3) + c - 48 ;
            c = getchar() ;
        }
        x *= f ;
    }
    
    inline void readl( ll &x ){
        x = 0 ; ll f = 1 ; char c = getchar() ;
        while( c < '0' || c > '9' ) {
            if( c == '-' ) f = -1 ;
            c = getchar() ;
        }
        while( c >= '0' && c <= '9' ) {
            x = (x << 1) + (x << 3) + c - 48 ;
            c = getchar() ;
        }
        x *= f ;
    }
    
    using namespace std ;
    
    #define N 2010
    
    int n , m , r , c , x , y ;
    char ch[ N ][ N ] ;
    struct edge {
    	int to , nxt , v ;
    } e[ N * N * 4 ] , E[ N * N * 4 ];
    int head[ N * N ] , cnt , Head[ N * N ] , Cnt ;
    int vis[ N * N ] , d[ N * N ] , Vis[ N * N ] , D[ N * N ] ;
    int q[ 1000100 ] ;
    
    void ins1( int u , int v , int w ) {
    	e[ ++ cnt ].to = v ;
    	e[ cnt ].nxt = head[ u ] ;
    	e[ cnt ].v = w ;
    	head[ u ] = cnt ;
    }
    
    void ins2( int u , int v , int w ) {
    	E[ ++ Cnt ].to = v ;
    	E[ Cnt ].nxt = Head[ u ] ;
    	E[ Cnt ].v = w ;
    	Head[ u ] = Cnt ;
    }
    
    void spfa() {
    	int s = (r-1) * m + c ;
    	q[ 1 ] = s ;
    	int l = 1 , r = 2 ;
    	for( int i = 1 ; i <= n * m ; i ++ ) d[ i ] = inf ;
    	d[ s ] = 0 ;
    	vis[ s ] = 1 ;
    	while( l != r ) {
    		int u = q[ l ++ ] ;
    		vis[ u ] = 0 ;
    		if( l == 1000000 ) l = 1 ;
    		for( int i = head[ u ] ; i ;  i = e[ i ].nxt ) {
    			int v = e[ i ].to ;
    			if( d[ v ] > d[ u ] + e[ i ].v ) {
    				d[ v ] = d[ u ] + e[ i ].v ;
    				if( !vis[ v ] ) {
    					vis[ v ] = 1 ; 
    					q[ r ++ ] = v ;
    					if( r == 1000000 ) r = 1 ;
    				}
    			}
    		}
    	}
    }
    
    void spfa2() {
    	int s = (r-1) * m + c ;
    	int l = 1 , r = 2 ;
    	q[ 1 ] = s ;Vis[ s ] = 1 ;
    	for( int i = 1 ; i <= n * m ; i ++ ) D[ i ] = inf ;
    	D[ s ] = 0 ;
    	while( l != r ) {
    		int u = q[ l ++ ] ;
    		Vis[ u ] = 0 ;
    		if( l == 1000000 ) l = 1 ;
    		for( int i = Head[ u ] ; i ;  i = E[ i ].nxt ) {
    			int v = E[ i ].to ;
    			if( D[ v ] > D[ u ] + E[ i ].v ) {
    				D[ v ] = D[ u ] + E[ i ].v ;
    				if( !Vis[ v ] ) {
    					Vis[ v ] = 1 ; 
    					q[ r ++ ] = v ;
    					if( r == 1000000 ) r = 1 ;
    				}
    			}
    		}
    	}
    }
    
    int main(){
    	in2( n , m ) ;
    	in2( r , c ) ;
    	in2( x , y ) ;
    	for( int i = 1 ; i <= n ; i ++ ) {
    		scanf( "%s" , ch[ i ] + 1 ) ;
    	}
    	for( int i = 1 ; i <= n ; i ++ ) {
    		for( int j = 1 ; j <= m ; j ++ ) {
    		    if( ch[ i ][ j ] == '*' ) continue ;
    			if(i-1>=1&&ch[i-1][j]=='.') ins1((i-1)*m+j,(i-2)*m+j,0),  ins2((i-1)*m+j,(i-2)*m+j,0);
    			if(j-1>=1&&ch[i][j-1]=='.') ins1((i-1)*m+j,(i-1)*m+j-1,1),ins2((i-1)*m+j,(i-1)*m+j-1,0);
    			if(i+1<=n&&ch[i+1][j]=='.') ins1((i-1)*m+j,i*m+j,0),      ins2((i-1)*m+j,i*m+j,0);
    			if(j+1<=m&&ch[i][j+1]=='.') ins1((i-1)*m+j,(i-1)*m+j+1,0),ins2((i-1)*m+j,(i-1)*m+j+1,1);
    		}
    	}
    	spfa() ;
    	spfa2() ;
    	int ans = 0 ;
    	for( int i = 1 ; i <= n * m ; i ++ ) {
    		if( d[ i ] <= x && D[ i ] <= y ) ans ++ ; 
    	}
    	printf( "%d
    " , ans ) ;
    }
    
  • 相关阅读:
    一次脑残的记录: Linux 中实时任务调度与优先级
    这 7 个 Linux 命令,你是怎么来使用的?
    物联网设备OTA软件升级之:完全升级和增量升级
    物联网设备OTA软件升级之:升级包下载过程之旅
    Linux应用程序设计:用一种讨巧方式,来获取线程栈的使用信息
    Linux系统中编译、链接的基石-ELF文件:扒开它的层层外衣,从字节码的粒度来探索
    应用程序设计:在动态库中如何调用外部函数?
    Typescript学习笔记
    gRPC 重试策略
    Gogs+Jenkins+Docker 自动化部署.NetCore
  • 原文地址:https://www.cnblogs.com/henry-1202/p/10349496.html
Copyright © 2020-2023  润新知