SDUT 2021 Spring Individual Contest(for 20) - 18(补题)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDUT 2021 Spring Individual Contest(for 20) - 18(补题)相关的知识,希望对你有一定的参考价值。

D - Counting Paths

A binary tree is a tree data structure in which each node has at most two children, which are referred to as the left child and the right child.

Consider an infinite binary tree with each node has exactly two children, and two given integers a and b, count the number of paths in the infinite binary tree that satisfy the following rules:

The path starts from the root of the tree.
The length of the path is equal to a (The length of a path is the total number of edges from the root to the final node on that path).
The number of change of direction along the path is equal to b. Change of direction means, going to your right child if you are the left child of your parent or vise versa.
As the number of paths can be too large, print it (modulo 109 + 7).

Input
The first line of the input contains an integer T (1 ≤ T ≤ 105), where T is the number of the test cases.

Each test case has one line that contains two integers a and b (0 ≤ b < a ≤ 105), the length of the path and the number of change of direction along it.

Output
For each test case, print a single integer that represents the number of paths that satisfy the mentioned rules (modulo 109 + 7).

Example
Input

2
2 1
4 3
Output
2
2
题意: 一颗满二叉树(往下可以无限延伸),给你路径长度a,改变方向次数b,问你满足这个条件的路径数有几条。答案要取模
思路: 就是组合数的思想,路径长度为a,那路上就会有a-1个拐点,一共要转向b次,也就是C(a-1,b),最后得数再✖2,期间求组合数要用到逆元,因为涉及到取模运算。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5 + 10, mod = 1e9 + 7;
int fact[N], infact[N];
int qmi(int q, int k, int p) {
    int res = 1;
    while (k) {
        if (k & 1) res = (ll)res * q % p;
        q = (ll)q * q % p;
        k >>= 1;
    }
    return res;
}
void init() {
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i++) {
        fact[i] = (ll)fact[i - 1] * i % mod;
        infact[i] = (ll)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    }
}

int main() {
    int t;
    scanf("%d", &t);
    init();
    while (t--) {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%lld\\n",
               (ll)2 * fact[a - 1] * infact[b] % mod * infact[a - b - 1] % mod);
    }
    return 0;
}

G - Super Subarray

In this problem, subarray is defined as non-empty sequence of consecutive elements.

We define a subarray as Super Subarray if the summation of all elements in the subarray is divisible by each element in it.

Given an array a of size n, print the number of Super Subarrays in a.

Input
The first line of the input contains a single integer T (1 ≤ T ≤ 100), the number of test cases.

The first line of each test case contains one integer n (1 ≤ n ≤ 2000), the length of array a.

The second line of each test case contains the sequence of elements of the array a1, a2, …, an (1 ≤ ai ≤ 109), ai is the i-th element of the array a.

Output
For each test case, print a single integer that represents the number of Super Subarrays in a, on a single line.

Example
Input

2
5
1 2 3 4 5
5
2 3 4 3 6
Output
6
6
题意: 给一个有n个数的数组,求给数组中有几个超级数组,超级数组的意思是:子区间的区间和是能整除该区间的每一个数。问有几个超级数组。
思路: 直接处理出前缀和,在循环中枚举每种情况的区间,并求出区间的最小公倍数,只要该区间和,能整除这个区间的最小公倍数,就是超级数组。
也可以利用前缀和+线段树处理出区间和和区间最小公倍数,再直接枚举。(虽说有点多此一举)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e3 + 10;
ll a[N], sum[N];

ll lcm(ll a, ll b) { return a / __gcd(a, b) * b; }

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int n, res = 0;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            sum[i] = sum[i - 1] + a[i];
        }
        
        for (int i = 1; i <= n; i++) {
            ll t = a[i];
            for (int j = i; j <= n; j++) {
                t = lcm(t, a[j]);
                ll num = sum[j] - sum[i - 1];
                if (t > sum[n]) {
                    break;
                } else if (num % t == 0) {
                    res++;
                }
            }
        }
        printf("%d\\n", res);
    }
    return 0;
}

顺便练一下,用线段树写区间最小公倍数

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
#define ll long long
struct node {
    int l,r;
    ll d;
}tr[N*4];
ll a[N],sum[N];
ll lcm(ll a,ll b) {
    return a/__gcd(a,b)*b;
}
void pushup(int u) {
    tr[u].d=lcm(tr[u<<1].d,tr[u<<1|1].d);
}
void build(int u,int l,int r) {
    if(l==r) {
        tr[u]={l,r,a[l]};
    }
    else {
        tr[u].l=l,tr[u].r=r;
        int mid=l+r>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
ll query(int u,int l,int r) {
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].d;
    else {
        int mid = tr[u].l + tr[u].r >> 1;
        ll res=1;
        if(l<=mid) {
            res=query(u<<1,l,r);
        } 
        if(r>mid){
            res=lcm(res,query(u<<1|1,l,r));
        } 
        return res;
    }    
}

int main() {
    int n;
    scanf("%d", &n);
    for(int i=1;i<=n;i++) {
        scanf("%lld",&a[i]);
    }
    build(1,1,n);
    int x,y;
    scanf("%d%d",&x,&y);
    printf("%lld\\n",query(1,x,y));
    return 0;
}

To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激

以上是关于SDUT 2021 Spring Individual Contest(for 20) - 18(补题)的主要内容,如果未能解决你的问题,请参考以下文章

SDUT 2021 Spring Individual Contest(for 20) - 1补题

SDUT 2021 Spring Individual Contest(for 20) - 17(补题)

SDUT 2021 Spring Individual Contest(for 20) - 15(补题)

SDUT 2021 Summer Individual Contest - 2(for 20)(补题)

SDUT 2021 Winter Individual Contest - N(B-Derangement)

2021-08-03SDUT 2021 Summer Individual Contest - 4(for 20)(补题)