2019 Blue Bridge Cup National Championship Group B Mock Problem Solution

label ok

1454456-20190513165515339-1807244021.png

#include<bits/stdc++.h>
using namespace std;

/*
求阶乘 去除尾部0
每次求阶乘时:结果去除尾0,并对 1e6取余
*/

typedef long long ll;

ll n = 1325476;
const ll mod = 1e6;

ll ans = 1;

void solve(){
    while(ans%10 == 0) ans = ans/10;
    ans = ans%mod;
}

int main(){
    for(ll i = n;i>=1;i--){
        ans = ans * i;
        solve();
    }
    printf("%lld",ans);
    return 0;
}
//137664
#include<bits/stdc++.h>
using namespace std;

/*
2 * 5会产生0
做法:每次循环求阶乘时 统计2和5个数 并去除2和5,最后乘回来即可 
*/

typedef long long ll;

ll n = 1325476;
const ll mod = 1e6;

ll ans = 1;
ll cnt1 = 0;
ll cnt2 = 0;
int main(){
    for(ll i = 1;i <= n; i++){
        ll x = i;
        while(x%2==0) cnt1++,x=x/2;
        while(x%5==0) cnt2++,x=x/5;
        ans = ans * x % mod;
    }
    if(cnt1 - cnt2 > 0){
        for(int i=1;i<=cnt1-cnt2;i++) ans = ans * 2 % mod;
    }else{
        for(int i=1;i<=cnt2-cnt1;i++) ans = ans * 5 % mod;
    }
    printf("%lld\n",ans);
    return 0;
}
//137664

101 string ok

1454456-20190513165528107-711086253.png

dfs search method

#include<bits/stdc++.h>
using namespace std;

int num[35];
long long ans = 0;

/*
dfs枚举2^30种可能结果
运行100秒左右
*/

void dfs(int k){
    if(k==31){
        for(int i=1;i<=28;i++){
            if(num[i] == 1 && num[i+1] == 0 && num[i+2] == 1){
                ans++;
                break;
            }
        }
        return;
    }
    
    num[k] = 1;
    dfs(k+1);
    num[k] = 0;
    dfs(k+1);
}


int main(){
    dfs(1);
    printf("%lld",ans);
    return 0;
}
//1046810092

binary enumeration method

#include<bits/stdc++.h>
using namespace std;

/*
二进制枚举
1<<30种 也就是2^30可能情况
对于每个情况 枚举每一位 判断是否满足条件 
*/

int ans = 0;

int main(){
    for(int i=0;i<(1<<30);i++){
        int x = i;
        int a = 0 ,b = 0, c = 0;
        bool check = false;
        while(x){
            c = b;
            b = a;
            a = x & 1;
            if(a && !b && c){
                check = true;
                break;
            }
            x >>= 1;
        }
        if(check) ans++;
    } 
    cout<<ans<<endl;
    return 0;
} 
//1046810092 

game ok

1454456-20190513165538656-1016185676.png
1454456-20190513195433885-413036102.png

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
LL a = 482333897982347239LL;
LL b = 557432748293424892LL;
LL k = 1389472389742429877LL;

//同余 (b-a) % mod = b*2 % mod 
void test(){
    LL mod = a + b;
    cout<<(b-a) % mod<<endl;
    cout<<b*2%mod<<endl;
} 

//快速乘:加法代替乘法 
LL mmul(LL x,LL y,LL p){
    LL ans = 0LL;
    while(y){
        if( y & 1LL) ans = (ans + x) % p;
        x = (x + x) % p;
        y >>= 1;
    }
    return ans;
}

//快速幂 
LL mpow(LL x,LL y,LL p){
    LL ans = 1LL;
    while(y){
        if(y & 1LL) ans = mmul(ans,x,p);
        x = mmul(x,x,p);
        y >>= 1;
    }
    return ans;
}

int main(){
    LL mod = a + b; //首先 c + d = 2*a + b - a  =  a + b = mod
    LL ans = mmul(a,mpow(2LL,k,mod),mod); //d = b - a = b - (mod - b) = 2*b - mod = 2*b %mod,所以 b-a 也就等价于 b*2,等价后a与b交不交换都无所谓(因为后面的操作都是*2)
    printf("%lld\n",min(ans,mod-ans));//结果确保A更小,A可能是ans 也可能是mod-ans(b)
    return 0;
} 
//383513242709218605

common divisor ok

Mr. Garantou has n numbers, and he wants to select k numbers from them so that their greatest common divisor is the largest.
Please find this greatest greatest common divisor.

Input format
Enter two integers on the first line.
Enter an integer on the second line.

Output format
Output an integer.

data range
1454456-20190513165713390-614305200.png

Sample Input 1
4 3
2 4 8 3
Sample Output 1
2

Sample Input 2
4 2
4 8 6 6
Sample Output 1
6

Ideas:
30% violent dfs or state compression (binary enumeration) selects k numbers and the
other 30% directly outputs 1 by probability.
100% enumerate possible gcd values ​​and check how many elements are divisible by it. Time complexity O(nlogn)

30% code - dfs search

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
ll ans = 1;
ll gcd(ll a,ll b){
    if(b==0)
        return a;
    return gcd(b,a%b);
}

const int maxn = 1e6+10;
int n,k;
int a[maxn];

/*
dfs暴搜过30%数据 
*/

/*
不确定的dp状态转移方程:dp[i][k] = max(dp[i][k],gcd(dp[j<i][k-1], a[i])
*/ 

void dfs(int cur,int have,ll _gcd){
    
    if(cur == n+1 && have == k+1){
        ans = max(ans,_gcd);
        return;
    }
    if(cur > n+1) return;
    if(have > k+1) return;
    if(have == 1){
        dfs(cur+1,have,_gcd);
        dfs(cur+1,have+1,a[cur]);
    }else{
        dfs(cur+1,have,_gcd);
        dfs(cur+1,have+1,gcd(a[cur],_gcd));
    }
    
}

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

100% code

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e6 + 7;
const int mod = 1e9 + 7;
int a[N+10];

int main(){
    int n,k,x;
    memset(a,0,sizeof(a));
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++){
        scanf("%d",&x);
        a[x]++;//x的个数+1 
    }
    int ans = 1;
    //枚举gcd可能出现的值:从i=2 ~ N; 
    for(int i = 2 ;i < N; i++){
        int cnt = 0;
        for(int j = i;j < N; j += i) cnt += a[j]; //能被i整除的数 一定是 i i+i i+i+i .... 
        if(cnt >= k) ans = i;//比k大 那么选出k个数 他们的gcd就是当前的i 
    }
    printf("%d\n",ans);
    return 0;
} 

garlic head ok

1454456-20190513170328144-1854660070.png
1454456-20190513170336338-104616719.png

In fact, it is to ask how many loops there are in the graph. The number of counted loops is k, and the result is 2^k-1.
30% state compression Select the edge, determine whether the selected edge constitutes a
100% ring, and check the number of counted rings, each query only needs to determine whether the two points are connected before, why the result is 2 ^k-1 (k represents the number of rings), a big guy said: The title shows that "as long as the garlic head diagram is formed, it is a case", then that is to say, taking 1 ring from the original image can also form a ring, Taking two of the rings can also form a ring (if there is a ring, it means that it is a subgraph of the garlic head graph, no matter how many rings you take, it is a garlic head graph).......C(n,i) i from 1~k can form a ring, then C(n,1) + C(n,2) + C(n,3) + C(n,k) is the answer, and the value of this formula is also equal to 2^k-1

100% code - and look up the number of statistic rings

#include<bits/stdc++.h>
using namespace std;

const int mod = 1046513837;
int n,m,f[200500];

int find(int x){
    return f[x] == x ? x : f[x] = find(f[x]);
}

void merge(int a,int b){
    int x = find(a);
    int y = find(b);
    if(x != y ) f[x] = y;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) f[i] = i;
    long long ans = 1;
    for(int i=1 ;i<=m;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        int x = find(a), y = find(b);
        if(x == y){//这里如果 两个点祖先一样 说明找到环了 
            ans <<= 1; 
            if(ans > mod) ans -= mod;
        }else merge(a,b);
        printf("%lld\n",ans-1);
    }
    return 0;
}

Interval and 60% line segment tree practice will not

1454456-20190513170354411-288803493.png
1454456-20190513170405661-1062588758.png

30% Calculate violently according to the meaning of the question, enumerate the weight interval, and enumerate the interval of the given array ok

60% Enumerate all the answer intervals l~r, and see which intervals can be divided into two disjoint intervals. If you do it violently: enumerate l and r for a total of O(n^2), and judge whether they are exactly divided into The two intervals are O(n^3) in total. Judging whether it is divided into two intervals can be maintained by the union query set, and the query complexity can be reduced to O(1).
How to use and check the maintenance? I didn't write the code, but I thought like this, in the original sequence, if a[i] and a[i-1] are consecutive, that is (the latter number is 1 greater than the former), add the current i-th number to the ith number In the set of i-1, it represents that they are an interval. When querying whether it is divided into two ranges later, you only need to query whether the numbers in the l~r range are divided into several sets.
I think there's no problem with this idea emmmmm

100% line segment tree maintains the maximum value of the interval, the second largest value, and the corresponding number O(nlogn) will not

30% code - brute force enumeration:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 3*1e6+5;
int n;
int m[maxn];
int vis[maxn];
int ans = 0;

/*
枚举l~r区间
枚举i~j区间
*/

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&m[i]);
    for(int l=1;l<=n;l++){
        for(int r=l+1;r<=n;r++){
            bool flag = false;
            for(int a=1;a<=n;a++){
                for(int b=a;b<=n;b++){
                    for(int c=b+1;c<=n;c++){
                        for(int d=c;d<=n;d++){
                            bool flag2 = true;
                            for(int i=1;i<=n;i++) vis[i] = 0;
                            for(int i=a;i<=b;i++) vis[m[i]] = 1;
                            for(int i=c;i<=d;i++) vis[m[i]] = 1;
                            for(int i=l;i<=r;i++){
                                if(vis[i] == 0){
                                    flag2 = false;
                                    break;
                                }
                            }
                            if(flag2 && r-l+1 == b-a+1 + d-c+1){
                                ans++;
                                flag = true;
                                //cout<<"l = "<<l<<" r = "<<r<<"a = "<<a<<" b = "<<b<<" c = "<<c<<" d = "<<d<<endl;
                                break;
                            }
                            if(flag) break;
                        }
                        if(flag) break;
                    }
                    if(flag) break;
                }
                if(flag) break;
            }
//          if(flag) continue;
        }
    }
    cout<<ans<<endl;
    return 0;
}
/*
5
5 4 3 1 2
*/

100% Code - Segment Tree

#include<cstdio>
#include<algorithm>
#define mid (l+r)/2
#define lt (s<<1)
#define rt (s<<1|1)
#define Mn 300005
using namespace std;
long long ans;
int fc[Mn*4],fm[Mn*4],sm[Mn*4],sc[Mn*4];
int p[Mn],nt[Mn],add[Mn*4],n,i,k1,k2,x;

void updata(int s)
{
    int k1=lt,k2=rt;
    if (fm[k1]>fm[k2]) swap(k1,k2);
    if (fm[k1]<fm[k2])
        {
            fm[s]=fm[k1],fc[s]=fc[k1];
            if (sm[k1]<fm[k2])
                sm[s]=sm[k1],sc[s]=sc[k1];
            else
                if (sm[k1]==fm[k2])
                    sm[s]=sm[k1],sc[s]=sc[k1]+fc[k2];
                else sm[s]=fm[k2],sc[s]=fc[k2];
        }
    if (fm[k1]==fm[k2])
        {
            fm[s]=fm[k1],fc[s]=fc[k1]+fc[k2];
            if (sm[k1]<sm[k2])
                sm[s]=sm[k1],sc[s]=sc[k1];
            else
                if (sm[k2]<sm[k1])
                    sm[s]=sm[k2],sc[s]=sc[k2];
                else sm[s]=sm[k2],sc[s]=sc[k1]+sc[k2];
        }
}
void pplus(int s,int up)
{
    fm[s]+=up; sm[s]+=up;
    add[s]+=up;
}
void push(int s)
{
    if (add[s]!=0)
        pplus(lt,add[s]),pplus(rt,add[s]),add[s]=0;
}
void work(int s,int l,int r,int ls,int rs,int up)
{
    if (l>rs || r<ls) return;
    if (ls<=l && r<=rs)
        return(void)(pplus(s,up));
    push(s);
    work(lt,l,mid,ls,rs,up);
    work(rt,mid+1,r,ls,rs,up);
    updata(s);
}
void build(int s,int l,int r)
{
    if (l==r) return(void)(fc[s]=1,sm[s]=1);
    build(lt,l,mid); build(rt,mid+1,r);
    updata(s);
}
void upans(int s,int l,int r,int ls,int rs)
{
    if (ls<=l && r<=rs)
        {
            if (fm[s]==1 || fm[s]==2) ans+=fc[s];
            if (sm[s]==1 || sm[s]==2) ans+=sc[s];
            return;
        }
    if (ls>r || l>rs) return;
    push(s);
    upans(lt,l,mid,ls,rs);
    upans(rt,mid+1,r,ls,rs);
    updata(s);
}
int main()
{
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        scanf("%d",&p[i]),nt[p[i]]=i;
    build(1,1,n);
    for(i=n;i>=1;i--)
        {
            x=nt[i];
            if (p[x+1]<i && p[x-1]<i) work(1,1,n,i,n,1);
            if (p[x+1]<i && p[x-1]>i) work(1,1,n,i,p[x-1]-1,1);
            if (p[x+1]>i && p[x-1]<i) work(1,1,n,i,p[x+1]-1,1);
            if (p[x+1]>i && p[x-1]>i)
                {
                    k1=p[x+1]; k2=p[x-1];
                    if (k1>k2) swap(k1,k2);
                    work(1,1,n,i,k1-1,1);
                    work(1,1,n,k2,n,-1);
                }
            upans(1,1,n,i,n);
        }
    printf("%lld",ans-n);
    return 0;
}

Reprinted in: https://www.cnblogs.com/fisherss/p/10857705.html

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324521471&siteId=291194637