zoukankan      html  css  js  c++  java
  • jxust摸底测试1

    题目
    A题意:n个瓶子排成一排,给出瓶子容量a[i],初始瓶子为空。m次操作:每次向x瓶中加入y容量的水,如果瓶子水有多则将多的水倒入下一个瓶子。
    问:最终每一个瓶子里的水量。
    解法:以前做这题的思路是模拟每一次加水并将多的水倒入下一水瓶。代码写的很烂。
    现在重新回顾这题思路就是,先不管瓶子容量直接加水,最后统一将多的水倒入下一瓶子。

    const int maxn = 1e5+9;
    int a[maxn] , b[maxn];
    void solve(){
        int n , m ;
        scanf("%lld%lld" , &n , &m);
        rep(i , 1 , n){
            b[i] = 0;
        }
        rep(i , 1 , n){
            scanf("%lld" , &a[i]);
        }
        rep(i , 1 , m){
            int x , y ;
            scanf("%lld%lld" , &x , &y);
            b[x] += y ;
        }
        rep(i , 1 , n){
            if(b[i] > a[i]){
                b[i+1] += b[i] - a[i];
                b[i] = a[i] ;
            }
        }
        rep(i , 1 , n-1){
            printf("%lld " , b[i]);
        }
        printf("%lld
    " , b[n]);
    }
    
    signed main()
    {
        int t ; scanf("%lld" , &t);while(t--)
        //int _ ;cin>>_;while(_--)
            solve();
    }
    

    B题意:给定一个整数n(4e4),能不能将其分解为三个素数之和,有多少种分法。(2,2,3)与(2,3,2)属于同一种。
    解法:打比赛的时候不敢想直接枚举,第一感觉就是必超时。回过头来分析一波,时间复杂度还是可行的。
    根据素数定理:1-4e4有大概有5e3个素数,暴力枚举两个素数,判断所剩的第三个数是否素数且递增。时间复杂度((n^2))1e7数量级可接受。

    const int maxn = 4e4+9;
    int prime[maxn] , len ;
    bool is_prime[maxn];
    void init(){
        ME(is_prime , true);
        is_prime[1] = false;
        rep(i , 2 , maxn){
            if(is_prime[i]){
                prime[++len] = i ;
    
                for(int j = i*i ; j <= maxn ; j += i){
                    is_prime[j] = false;
                }
            }
        }
    }
    
    void solve(){
        int n , cnt = 0;
        scanf("%lld" , &n);
        for(int i = 1 ; i <= len && prime[i] < n; i++){
            for(int j = i ; j <= len && prime[i] + prime[j] < n && n-prime[i]-prime[j] >= prime[j] ; j++){
                int k = n - prime[i] - prime[j] ;
                if(is_prime[k] && k >= prime[j]){
                    cnt++;
                }
            }
        }
        cout << cnt << endl;
    }
    

    C题意:n(2e5)个坐标点(x,y,z),连接两个点的花费为(MIN(|X_u−X_v|,|Y_u−Y_v|,|Z_u−Z_v|),将n个点连起来最小花费为多少)
    解法:稍一分析可以知道是最小生成树问题,难在如何建图,分别以x,y,z排序并以其建图,可得3*(n-1)条边,直接上Kruskal。

    const int maxn = 2e5+9;
    int fa[maxn];
    int len ;
    struct node{
        int x , y , z , id;
    }p[maxn];
    
    struct edge{
        int u , v , val;
    }e[maxn*3];
    
    void AddEdge(int u , int v , int w){
        e[++len].u = u ;
        e[len].v = v ;
        e[len].val = w ;
    }
    
    int cal(int x , int y){return abs(x - y);}
    bool cmp(edge a , edge b){return a.val < b.val;}
    bool cmp1(node a , node b){return a.x < b.x;}
    bool cmp2(node a , node b){return a.y < b.y;}
    bool cmp3(node a , node b){return a.z < b.z;}
    int find(int x){
        if(x != fa[x]){
            return fa[x] = find(fa[x]);
        }
        return fa[x];
    }
    void unite(int x , int y){
        x = find(x) , y = find(y);
        fa[x] = y ;
    }
    void solve(){
        int n ;
        scanf("%d" , &n);
        rep(i , 1 , n) fa[i] = i ;
        rep(i , 1 , n){
            scanf("%d%d%d" , &p[i].x , &p[i].y , &p[i].z);
            p[i].id = i ;
        }
        sort(p+1 , p+1+n , cmp1);
        rep(i , 2 , n){
            AddEdge(p[i].id , p[i-1].id , cal(p[i].x , p[i-1].x));
        }
        sort(p+1 , p+1+n , cmp2);
        rep(i , 2 , n){
            AddEdge(p[i].id , p[i-1].id , cal(p[i].y , p[i-1].y));
        }
        sort(p+1 , p+1+n , cmp3);
        rep(i , 2 , n){
            AddEdge(p[i].id , p[i-1].id , cal(p[i].z , p[i-1].z));
        }
        ll ans = 0 ;int cnt = 0 ;
        sort(e+1 , e+1+len , cmp);
        rep(i , 1 , len){
            int u , v , w ;
            u = e[i].u , v = e[i].v , w = e[i].val;
            if(find(fa[u]) != find(fa[v])){
                unite(u , v);
                ans += w ;
                cnt++;
            }
            if(cnt == n-1) break;
        }
        printf("%lld
    " , ans);
    }
    

    D题意:数位dp,以后再补。
    E题意:给出一个整数n,将其分解为若干个正整数之和,使得这些正整数的乘积x最大。计算(frac{1}{n}modx)(数据保证gcd(n,x)=1)
    就是求n模x下的逆元,首先求出x,分析将x可知尽可能分解多3,可得x最大.
    因为x求出来不能保证是质数,所以不能使用费马小定理求逆元,而应该使用扩展欧几里得求解.

    int x , y , d ;
    int quickpow(int a , int b){
        int ans = 1 ;
        while(b){
            if(b&1){
                ans = ans * a ;
            }
            b >>= 1 ;
            a = a * a ;
        }
        return ans ;
    }
    void ex_gcd(int a , int b , int &d , int &x , int &y){
        if(!b){
            d = a ;
            x = 1 ;
            y = 0;
        }else{
            ex_gcd(b , a%b , d , x , y);
            int t = x ;
            x = y ;
            y = t - (a/b)*y;
        }
    }
    
    int inv(int a , int b){
        if(gcd(a,b)!=1) return 0;//判断是否存在逆元
        ex_gcd(a , b , d , x , y);
        int t = b/d;
        return (x%t+t)%t;//得最小正整数解
    }
    
    void solve(){
        int n , x ;
        cin >> n ;
        if(n % 3 == 0){
            x = quickpow(3 , n/3);
        }else if(n % 3 == 1){
            x = quickpow(3 , n/3-1)*4;
        }else{
            x = quickpow(3 , n/3)*2;
        }
        cout << inv(n , x) << endl;
    }
    

    F题意:n(1e5)个数,m(1e5)个操作,n个数初始为0,
    两种操作区间修改和获取单点值
    1、[l,r]区间数翻转0变1,1变0。
    2、问下标x数为多少。
    解法:直接暴力的话翻转过程时间复杂度O((n))m次操作必超时,所以使用树状数组将区间翻转复杂度降为O(logn),相应得获取某个数得操纵升为O(logn).

    int n , m ;
    int a[maxn];
    int lowerbit(int x){
        return x&(-x);
    }
    
    void update(int x , int y){
        while(x <= n){
            a[x] += y ;
            x += lowerbit(x);
        }
    }
    int getsum(int x){
        int ans = 0;
        while(x >= 1){
            ans += a[x];
            x -= lowerbit(x);
        }
        return ans ;
    }
    
    void solve(){
        scanf("%lld%lld" , &n , &m);
        while(m--){
            int t ;
            scanf("%lld" , &t);
            if(t == 1){
                int l , r ;
                scanf("%lld%lld" , &l , &r);
                update(l , 1);
                update(r+1 , -1);
            }else{
                int x ;
                scanf("%lld" , &x);
                printf("%lld
    " , getsum(x)%2);
            }
        }
    }
    

    F题意:有n个人,现在有一个聚会,每个人都可以选择参加或者不参加。而参加的人中每个人要么只去送礼物,要么只接受礼物。
    不存在全部都接受礼物或者全部都送礼物的情况(这样要么没人送礼物,要么没人接受礼物了)。问有多少中情况?、
    解法:手玩几个数据就可得出规律,组合数问题。

    const int maxn = 1e5+9;
    const int N = 1e6+7;
    int fac[maxn] , inv[maxn];
    void init(){
        fac[0] = inv[1] = inv[0] = 1;
        rep(i , 1 , maxn-1){
            fac[i] = fac[i-1] * i % mod ;
        }
        inv[maxn-1] = quickpow(fac[maxn-1] , mod-2);
        red(i , maxn-2 , 1){
            inv[i] = inv[i+1]%mod * (i+1)%mod;
        }
    }
    int C(int n , int m){
        return fac[n] % mod * inv[m] % mod * inv[n-m] % mod ;
    }
    void solve(){
        init();
        int n ;
        cin >> n ;
        int ans = 0 ;
        rep(i , 2 , n){
            ans = ans % mod + C(n,i)%mod*(quickpow(2,i)-2+mod)%mod;
        }
        cout << ans%mod << endl;
    }
    

    H题意:现在有两个相同大小的地图,左上角为起点,右下角问终点。问是否存在同一条最短路径。最短距离一样,他们走的路径也一样。
    解法:三次bfs,第一次对第一个图bfs求出最短路径,第二次对第二个图求出bfs最短路径,如果相等(确保距离相等),再将两个图合并bfs(确保两条最短路径是一样得),比较是否相等。
    简化一下对第一个求一次bfs,再求一次合并图得最短路径。

    const int maxn = 5e2+9;
    char s1[maxn][maxn];
    char s2[maxn][maxn];
    int n , m ;
    int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
    int vis[maxn][maxn];
    
    struct node{
        int x , y , w ;
    };
    int bfs(int x , int y , char s[][maxn]){
        ME(vis , false);
        queue<node>q;
        node now = {x  , y , 0} , next;
        q.push(now);
        while(!q.empty()){
            now = q.front();q.pop();
            if(now.x==n&&now.y==m){
                return now.w;
            }
            rep(i , 0 , 3){
                int xx = now.x + dir[i][0];
                int yy = now.y + dir[i][1];
                int ww = now.w + 1 ;
                if(vis[xx][yy] || xx < 1 || xx > n || yy < 1 || yy > m || s[xx][yy] == '#'){
                    continue;
                }
                vis[xx][yy] = 1 ;
                next.x = xx , next.y = yy , next.w = ww ;
                q.push(next);
            }
        }
        return -1 ;
    }
    
    void solve(){
        scanf("%lld%lld" , &n , &m);
        rep(i , 1 , n){
            scanf("%s" , s1[i]+1);
        }
        rep(i , 1 , n){
            scanf("%s" , s2[i]+1);
        }
        rep(i , 1 , n){
            rep(j , 1 , m){
                if(s1[i][j] == '*' && s2[i][j] == '#'){
                    s1[i][j] = '#';
                }
            }
        }
        int ans1 = bfs(1 , 1 , s2);
        int ans2 = bfs(1 , 1 , s1);
        if(ans1 == ans2 && ans1 != -1){
            cout << "YES" << endl;
        }else{
            cout << "NO" << endl;
        }
    }
    
    

    I题是水题不多说

  • 相关阅读:
    学习笔记之Linux开发(C语言)
    Shell脚本文件操作
    学习笔记之Shell脚本的输出重定向
    学习笔记之正则表达式 (Regular Expressions)
    学习笔记之#pragma
    eclipse启动不了报错java was started but returned exit code=13
    学习笔记之APACHE ANT
    学习笔记之Linux / Shell
    学习笔记之DB2 9 Fundamentals 730
    windows远程关机重启
  • 原文地址:https://www.cnblogs.com/nonames/p/13111347.html
Copyright © 2011-2022 走看看