牛客网暑期ACM多校训练营(第一场)

A
推了推发现成了原题,直接度了一发随便改改就过了
原题参考 https://blog.csdn.net/MIECZ/article/details/80591212

#define IN_LB() freopen("C:\\Users\\acm2018\\Desktop\\in.txt","r",stdin)
#define OUT_LB() freopen("C:\\Users\\acm2018\\Desktop\\out.txt","w",stdout)
#define IN_PC() freopen("C:\\Users\\hz\\Desktop\\in.txt","r",stdin)
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 200005;
ll fac[maxn],MOD = 1e9+7;

void init() {
    int i;
    fac[0] =1;
    for(i =1; i <= (int)2e5+10; i++) //modify
        fac[i] = fac[i-1]*i % MOD;
}

ll fastpow(ll a, ll b) {
    ll tmp = a % MOD, ans =1;
    while(b) {
        if(b &1)
            ans = ans * tmp % MOD;
        tmp = tmp*tmp % MOD;
        b >>=1;
    }
    return ans;
}

ll comb(ll n, ll m) {
    return  m>n ? 0 : fac[n]*fastpow(fac[m]*fac[n-m], MOD-2) % MOD;
}

ll Lucas(ll n, ll m) {
    return m ? (comb(n%MOD, m%MOD)*Lucas(n/MOD, m/MOD))%MOD : 1;
}

int main() {
//    IN_LB();
    init();
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        n+=2,m+=2;
        cout<<(Lucas(n+m-4,n-2)*Lucas(n+m-4,n-2)%MOD-Lucas(n+m-4,n-1)*Lucas(n+m-4,m-1)%MOD+MOD)%MOD<<endl;
    }
    return 0;
}

B
oeis了之后找到了递推式

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    ll k,mod;
    while(cin>>k>>mod){
        ll n=0,a=1,b=0,c=1;
        for(int i=1;i<=k;i++){
            ll tmp=n*(b+c)-n*(n-1)/2*a;
            tmp%=mod;
            if(tmp<0)tmp+=mod;
            a=b,b=c;
            c=tmp;
            n++;
        }
        cout<<c<<endl;
    }
}

D
n! n ! 暴力枚举同构,除以自同构

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

int n,na,nb,m,ans,tota,totb,id[10],u[1007],v[1007],ta[10],tb[10];
bool f[10][10],g[10][10],vis[10];

inline bool pd (){
    // for (int i=1;i<=tota;i++)cout<<i<<' '<<ta[i]<<endl;
    for (int i=1;i<=tota;i++){
        for (int j=i;j<=tota;j++){
            if (f[i][j]!=f[ta[i]][ta[j]])return false;
        }
    }
    // cout<<1<<endl;
    return true;
}

void pre (int tmp){
    if (tmp>tota){
        if (pd ())m++;
        return ;
    }
    for (int i=1;i<=tota;i++){
        if (!vis[i]){
            vis[i]=1;
            ta[tmp]=i;
            pre(tmp+1);
            vis[i]=0;
        }
    }
}

inline bool pd2 (){
    for (int i=1;i<=tota;i++){
        for (int j=i;j<=tota;j++){
            if (f[i][j]&&!g[tb[i]][tb[j]])return false;
        }
    }
    return true;   
}

void work (int tmp){
    if (tmp>tota){
        if (pd2 ())ans++;
        return ;
    }
    for (int i=1;i<=totb;i++){
        if (!vis[i]){
            vis[i]=1;
            tb[tmp]=i;
            work(tmp+1);
            vis[i]=0;
        }
    }
}

void init (){
    memset (f,0,sizeof (f));
    memset (g,0,sizeof (g));
    memset (vis,0,sizeof (vis));
    m=ans=tota=totb=0;
    for (int i=1;i<=na;i++){
        scanf ("%d%d",&u[i],&v[i]);
        vis[u[i]]=1;
        vis[v[i]]=1;
    }
    for (int i=1;i<=n;i++){
        if (vis[i]){
            id[i]=++tota;
        }
    }
    for (int i=1;i<=na;i++){
        f[id[u[i]]][id[v[i]]]=1;
        f[id[v[i]]][id[u[i]]]=1;
        // cout<<id[u[i]]<<' '<<id[v[i]]<<endl;
    }

    memset (vis,0,sizeof (vis));
    pre (1);

    memset (vis,0,sizeof (vis));
    for (int i=1;i<=nb;i++){
        scanf ("%d%d",&u[i],&v[i]);
        vis[u[i]]=1;
        vis[v[i]]=1;
    }
    for (int i=1;i<=n;i++){
        if (vis[i]){
            id[i]=++totb;
        }
    }
    for (int i=1;i<=nb;i++){
        g[id[u[i]]][id[v[i]]]=1;
        g[id[v[i]]][id[u[i]]]=1;
        // cout<<id[u[i]]<<' '<<id[v[i]]<<endl;
    }
    memset (vis,0,sizeof (vis));
    work (1);
}

int main (){
    while (~scanf ("%d%d%d",&n,&na,&nb)){
        init ();
        // cout<<ans<<' '<<m<<endl;
        ans/=m;
        printf("%d\n",ans);
    }
    return 0;
}

E
参考这个题dp部分的去重思路就行了 http://acm.hdu.edu.cn/showproblem.php?pid=6155

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

const int mod=1e9+7;
int n,m,K,f[100007][15][15],a[100007];

void work (){
    int i,j,k;
    for (i=1;i<=n;i++){
        for (k=1;k<=m;k++){
            if (i==k)
                f[i][0][k]=1;
            else f[i][0][k]=0;
            // cout<<i<<' '<<0<<' '<<k<<f[i][0][k]<<endl;
        }
        for (j=1;j<=K;j++){
            if (a[i]==j)f[i][j][0]=1;
            else f[i][j][0]=0;
                // cout<<i<<' '<<j<<' '<<0<<' '<<f[i][j][0]<<endl;
            for (k=1;k<=min(m,i-1);k++){
                f[i][j][k]=0;
                if (a[i]==j){
                    int sum=0;
                    for (int p=0;p<=K;p++){
                        sum=(sum+f[i-1][p][k])%mod;;
                    }
                    f[i][j][k]=(f[i][j][k]+sum)%mod;
                }
                else {
                    f[i][j][k]=f[i-1][j][k-1];
                }
                // cout<<i<<' '<<j<<' '<<k<<' '<<f[i][j][k]<<endl;
            }
            for (;k<=m;k++){
                f[i][j][k]=0;
            }
        }
    }
    int ans=0;
    for (int i=1;i<=K;i++){
        ans=(ans+f[n][i][m])%mod;
    }
    printf("%d\n",ans);
}

int main(){
    while (~scanf ("%d%d%d",&n,&m,&K)){
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        work ();
    }
    return 0;
}

F
贴了个求 ni=1ik ∑ i = 1 n i k 的板子,排序之后,枚举最大值取到相邻两个上界之间的区间上的贡献,求个和就行了。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=2005,mo=1e9+7;

typedef long long LL;

int T,k,b[maxn],c[maxn][maxn],Inv[maxn],ans,tmp;


LL calc(LL n,int k){
    n++; n%=mo; tmp=n;
    ans=0;
    for (int i=1;i<=k+1;i++)
    {
        ans=(ans+(LL)c[k+1][i]*b[k+1-i]%mo*n%mo) % mo;
        n=(LL)n*tmp % mo;
    }
    ans=(LL)ans*Inv[k+1] % mo;
    return ans;
}

LL a[1003];
LL n;

LL pow(LL n,LL p){
    LL ans=1;
    LL base=n;
    while(p){
        if(p&1){
            ans=ans*base%mo;
        }
        base=base*base%mo;
        p>>=1;
    }
    return ans;
}
int main()
{
    c[0][0]=1;
    for (int i=1;i<maxn;i++)
    {
        for (int j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j]) % mo;
        c[i][0]=1;
    }
    Inv[1]=1;
    for (int i=2;i<maxn;i++) Inv[i]=(LL)Inv[mo % i] * (mo-mo/i) % mo;
    b[0]=1;
    for (int i=1;i<maxn;i++)
    {
        b[i]=0;
        for (int k=0;k<i;k++) b[i]=(b[i]+(LL)c[i+1][k]*b[k] % mo) % mo;
        b[i]=((LL)b[i]*(-Inv[i+1]) % mo+mo)%mo;
    }


    while(~scanf("%lld",&n)){
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        sort(a+1,a+1+n);
        LL mul=1;
        LL sum=0;
        for(int i=1;i<=n;i++){
            if(a[i]==a[i-1]){
                mul=mul*a[i]%mo;
                continue;
            }
            LL k=n-i+1;
            LL tmp=pow(a[i],k+1)-pow(a[i-1],k)*(a[i-1]+1);
            tmp%=mo;
            if(tmp<0)tmp+=mo;
            LL p1=calc(a[i]-1,k)-calc(a[i-1],k);
            tmp-=p1;
            tmp%=mo;
            if(tmp<0)tmp+=mo;
            sum=(sum+tmp*mul)%mo;
            mul=mul*a[i]%mo;
        }
        printf("%lld\n",sum);
    }
}

I
3! 3 ! 枚举映射,倍长,用SA统计不同字串的个数,除以6去重,只含有单个字符的除以3

//SA
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=305000;
typedef long long ll;
int s[maxn];
int sa[maxn], t[maxn], t2[maxn], c[maxn], n;
int Rank[maxn], height[maxn];
void build_sa(int m, int n){
    int i, *x=t, *y=t2;
    for(i=0;i<m;i++)c[i]=0;
    for(i=0;i<n;i++)c[x[i]=s[i]]++;
    for(i=1;i<m;i++)c[i]+=c[i-1];
    for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(int k=1;k<=n;k<<=1){
        int p=0;
        for(i=n-k;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[y[i]]]++;
        for(i=1;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
        swap(x, y);
        p=1;x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
void geth(int n){
    int i, j, k=0;
    for(i=0;i<n;i++)Rank[sa[i]]=i;
    for(i=0;i<n;i++){
        if(k)k--;
        if(Rank[i]==0)break;
        j=sa[Rank[i]-1];
        while(s[i+k]==s[j+k])k++;
        height[Rank[i]]=k;
    }
}

int tot;
char str[50003];
void add(int a,int b,int c){
    for(int i=0;i<n;i++){
        if(str[i]=='a'){
            s[tot++]=a;
        }
        else if(str[i]=='b'){
            s[tot++]=b;
        }
        else {
            s[tot++]=c;
        }
    }
}

int main()
{
    /*n=8;
      s[8]=0;
      s[0]=s[1]=2;
      s[2]=s[3]=s[4]=s[5]=1;
      s[6]=s[7]=3;
      build_sa(200, n+1);
      geth(n+1);
      for(int i=0;i<=n;i++){
      printf("%d ", sa[i]);
      }
      printf("\n");
      for(int i=1;i<=n;i++){
      printf("%d ", height[i]);
      }
      printf("\n");*/
    while(~scanf("%d%s",&n,str)){
        tot=0;
        add(1,2,3);
        s[tot++]=0;
        add(1,3,2);
        s[tot++]=0;
        add(2,1,3);
        s[tot++]=0;
        add(2,3,1);
        s[tot++]=0;
        add(3,1,2);
        s[tot++]=0;
        add(3,2,1);
        s[tot++]=0;
        build_sa(10,tot);
        geth(tot);
        ll sum=0;
        int last=0;
        for(int i=6;i<tot;i++){
            int tmp=n-sa[i]%(n+1);
            int tadd=tmp-min(height[i],min(last,tmp));
            sum+=tadd;
            last=tmp;
        }
        ll sig=0;
        ll len=0;
        for(int i=0;i<n;i++){
            if(i>0&&str[i]!=str[i-1]){
                sig=max(sig,len);
                len=1;
            }
            else len++;
        }
        sig=max(sig,len);
        //cout<<sum<<' '<<sig<<endl;
        printf("%lld\n",(sum+sig*3)/6);
    }
}

J
莫队加上奇偶排序的常数优化就卡过去了

#include <bits/stdc++.h>
using namespace std;
int a[100003];
int n,q;
struct que{
    int l,r,id;
}rec[100003];
int bsize;
bool cmp(que a,que b){
    if(a.l/bsize==b.l/bsize){
        if((a.l/bsize)%2)return a.r<b.r;
        else return a.r>b.r;
    }
    return a.l/bsize<b.l/bsize;
}
int c[100003];
int tmp,tl,tr;
int ans[100003];
inline void update(int x,int add){
    if(add==1){
        if(c[x]==0)tmp++;
        c[x]++;
    }
    else {
        if(c[x]==1)tmp--;
        c[x]--;
    }
}
int main(){
    while(~scanf("%d%d",&n,&q)){
        bsize=sqrt(q);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=q;i++){
            scanf("%d%d",&rec[i].l,&rec[i].r);
            rec[i].id=i;
        }
        memset(c,0,sizeof(c));
        tmp=0;
        tl=0,tr=n+1;
        sort(rec+1,rec+1+q,cmp);
        for(int i=1;i<=q;i++){
            while(tl<rec[i].l){
                update(a[++tl],1);
            }
            while(tr>rec[i].r){
                update(a[--tr],1);
            }
            while(tl>rec[i].l){
                update(a[tl--],-1);
            }
            while(tr<rec[i].r){
                update(a[tr++],-1);
            }
            ans[rec[i].id]=tmp;
        }
        for(int i=1;i<=q;i++)printf("%d\n",ans[i]);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值