牛客练习赛68(A B C)

Practice link: https://ac.nowcoder.com/acm/contest/7079

 


A : 牛牛的mex

 

思路:考虑给出条件:$0<=a{}_{n}<=n-1$ 且每个数字不相同,因此区间 $\left[ l,r\right]$ 的mex就是区间 $\left[ 1,l-1\right]$   和 $\left[ r+1,n\right]$  中的最小值。

         只需要从前到后 和 从后到前维护两个min。

代码:

#include<bits/stdc++.h>
#define ll long long
#define MOD 1000000007 
#define INF 0x3f3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))  
#define _for(i,a,b) for(int i=a; i< b; i++)
#define _rep(i,a,b) for(int i=a; i<=b; i++)
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;
const int MAXN = 200005 ;
inline int rd() 
{
    int res = 0,flag = 0;
    char ch;
    if ((ch = getchar()) == '-')flag = 1;
    else if(ch >= '0' && ch <= '9')res = ch - '0';
    while ((ch = getchar()) >= '0' && ch <= '9')res = (res<<1) + (res<<3) + (ch - '0');
    return flag ? -res : res;
}
int min1[100005],min2[100005];
int a[100005];
int n,q;
int main()
{
    cin>>n>>q;
    min1[0]=n;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        min1[i]=min(min1[i-1],a[i]);
    }
    min2[n+1]=n;
    for(int i=n;i>=1;i--){
        min2[i]=min(min2[i+1],a[i]);
    }
    while(q--){
        int l,r;
        scanf("%d %d",&l,&r);
        printf("%d\n",min(min1[l-1],min2[r+1]));
    }
    return 0;
}

 

B:牛牛的算术

思路:考虑公式

         $\prod^{n}_{i=1} \sum^{i}_{j=1} \sum^{j}_{k=1} $ = $\prod^{n}_{i=1} i\sum^{i}_{j=1} j\sum^{j}_{k=1} k$

         那么因为有阶乘,所以当 n>199999 时,答案为 0 。

         n<199999时,我们看公式,可以用前缀和计算出 1 ~ 199999 的所有答案,推柿子

         ans = $\prod^{n}_{i=1} i\sum^{i}_{j=1} j\frac{j\times (j+1)}{2}$  

         也就是求一个 $x[n]=\sum^{n}_{i=1} i\times \frac{i\times (i+1)}{2}$ ,最后 $sum[n]=\prod^{n}_{i=1} i\times x[i]$ .

代码:

#include<bits/stdc++.h>
#define ll long long
#define MOD 199999 
#define INF 0x3f3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))  
#define _for(i,a,b) for(int i=a; i< b; i++)
#define _rep(i,a,b) for(int i=a; i<=b; i++)
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

using namespace std;
const int MAXN = 200005 ;
inline int rd() 
{
    int res = 0,flag = 0;
    char ch;
    if ((ch = getchar()) == '-')flag = 1;
    else if(ch >= '0' && ch <= '9')res = ch - '0';
    while ((ch = getchar()) >= '0' && ch <= '9')res = (res<<1) + (res<<3) + (ch - '0');
    return flag ? -res : res;
}
string s;
ll x[200005];
ll num[200005];
ll p;
int main()
{
    int T;
    p=1;
    x[1]=1;
    for(int i=2;i<199999;i++){
        p=p+i;
        x[i]=(1ll*x[i-1]%MOD)+((p*i)%MOD);
        x[i]=x[i]%MOD;
    }
    num[1]=1;
    for(int i=2;i<199999;i++){
        num[i]=(num[i-1]%MOD)*((i*x[i])%MOD);
        num[i]=num[i]%MOD;
    }
    cin>>T;
    while(T--){
        cin>>s;
        if(s.length()>=7){
            printf("0\n");
        }else{
            int n=0;
            for(int i=0;i<s.length();i++){
                n=n*10+(s[i]-'0');
                //cout<<s[i]<<endl;
            }
            //cout<<n<<endl;
            if(n>=MOD){
                printf("0\n");
            }else{
                printf("%lld\n",num[n]%MOD);
            }
        }
    }    
    return 0;
}

/*
1 1*1*1
2 (1*1*1)*(2*((1+2)+(1+(1+2))))
3 (1*1*1)*(2*((1+2)+(1+(1+2))))*(3*((1+2+3)*(1+(1+2)+(1+2+3))))

7   1*1+2*3
25  1*1+2*3+3*6

(1*1)+(2*(1+2))
(1*1)+(2*(1+2))+(3*(1+2+3))
 */

 

C:牛牛的无向图

思路:首先有 d(u,v)是u到v的最短距离,因此所有点一定是在一棵最小生成树上,其它边都可舍弃。然后考虑最小生成树的加边过程,就是从小到大的,然后我们可以用并查集维护各个连通块,对与某一次合并u和v,因为u和v的距离是w,因此sum[i]就是小于等于w时的数量,也就是sum[i] = sum[i-1]+ siz[fa[u]]*siz[fa[v]] ,其中siz[fa[u]]是点u所在点连通块的点数,最后对每一个L[i]在sum里进行二分查找答案即可。

代码:

//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
#define ll long long
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define mem(a,x) memset(a,x,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int maxn=500005;
inline int rd() {
    int res = 0,flag = 0;
    char ch;
    if ((ch = getchar()) == '-')flag = 1;
    else if(ch >= '0' && ch <= '9')res = ch - '0';
    while ((ch = getchar()) >= '0' && ch <= '9')res = (res<<1) + (res<<3) + (ch - '0');
    return flag ? -res : res;
}
/*
int head[maxn];
int num=0;
struct edg{
    int next,to,w;
}edge[maxn];
void add_edge(int u,int v,int w)
{
    num++;
    edge[num].next=head[u];edge[num].to=v;edge[num].w=w;head[u]=num;
    edge[++num].next=head[v];edge[num].to=u;edge[num].w=w;head[v]=num;
} */
//-----------
unsigned int SA, SB, SC;
int n, m, q, LIM;
int L[maxn];
int p[maxn];
int siz[maxn];
ll sum[maxn];
int chosen[maxn];
struct Node{
    int u,v,w;
}node[maxn];
bool cmp(Node x,Node y)
{
    return x.w<y.w;
}
unsigned int rng61(){
    SA ^= SA << 16;
    SA ^= SA >> 5;
    SA ^= SA << 1;
    unsigned int t = SA;
    SA = SB;
    SB = SC;
    SC ^= t ^ SA;
    return SC;
}

void gen(){
    scanf("%d%d%d%u%u%u%d", &n, &m, &q, &SA, &SB, &SC, &LIM);
    for(int i = 1; i <= m; i++){
        node[i].u = rng61() % n + 1;
        node[i].v = rng61() % n + 1;
        node[i].w = rng61() % LIM;
    }
    for(int i = 1; i <= q; i++){
        L[i] = rng61() % LIM;
        p[i] = L[i];
    }
}
int fa[maxn];
int find(int x)
{
    return (fa[x]==x)?x:fa[x]=find(fa[x]);
}
void merge(int u,int v)
{
    u=find(u);
    v=find(v);
    if(siz[u]>siz[v]){
        fa[v]=fa[u];
        siz[u]+=siz[v];
    }else{
        fa[u]=fa[v];
        siz[v]+=siz[u];
    }
}
int main()
{
    gen();
    for(int i=1;i<=n;i++){
        siz[i]=1;
        fa[i]=i;
    }
    sort(p+1,p+1+q);
    sort(node+1,node+m+1,cmp);
    int iter=0;
    sum[0]=0;
    for(int i=1;i<=m;i++){
        if(iter==n-1){
            break;
        }
        int u=node[i].u,v=node[i].v,w=node[i].w;
        if(find(u)!=find(v)){
            iter++;
            sum[iter]=sum[iter-1]+1ll*siz[fa[u]]*siz[fa[v]];
            chosen[iter]=w;
            merge(u,v);
        }
    }
    ll ans=0;
    for(int i=1;i<=q;i++){
        int l=0,r=iter,mid;
        while(l<r){
            mid=(l+r+1)>>1;
            if(L[i]>=chosen[mid]){
                l=mid;
            }else{
                r=mid-1;
            }
        }
        ans^=sum[l];
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2020-08-29 20:22  hachuochuo  阅读(162)  评论(0编辑  收藏  举报