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\n" , 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\n" , 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\n" , 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题是水题不多说

posted @ 2020-06-13 00:25  无名菜鸟1  阅读(100)  评论(0)    收藏  举报