2019 年西安电子科技大学程序设计竞赛新生赛网络赛

打了场新生赛,觉得自己不仅输在终点,还输在了起跑线。

a.把每一个数组分成任意段,每段异或起来,让异或和最大

解:简单发现a^b<=a+b,所以最好的方法就是每个数字都是一段,答案就是数组求个和

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>
 
using namespace std;
 
typedef long long ll;
const int maxn=100+10;
 
int main(){
    int n;
    scanf("%d",&n);
    int num=0;
    for(int i=0;i<n;i++){
        int x;
        scanf("%d",&x);
        num+=x;
    }
    printf("%d\n",num);
    return 0;
}

b.在一个二维平面上,每个人都会沿着一个方向走,当撞在一起时,他会继承其他人的方向,每个人只能被继承一次

经典弹性碰撞问题,在不考虑每个物品最后走到哪里只考虑时间的时候,直接忽略碰撞即可。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>
 
using namespace std;
 
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    int maxx=0;
    for(int i=0;i<m;i++){
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(z==1){
            maxx=max(maxx,x);
        }else if(z==2){
            maxx=max(maxx,n+1-y);
        }else if(z==3){
            maxx=max(maxx,n+1-x);
        }else{
            maxx=max(maxx,y);
        }
    }
    printf("%d\n",maxx);
    return 0;
}

c.有个人有X的时间和Y的脑细胞,做第i题要死xi个脑细胞和消耗yi的时间,问最多可以做多少题

二维费用背包模板题,顺便维护一下方案数就可以了

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>
 
using namespace std;
 
typedef long long ll;
const int mod=1e9+7;
const int maxn=100+10;
const int maxm=1e5+10;
ll w[maxm];
ll v[maxm];
 
ll f[maxn][maxn];
ll dp[maxn][maxn];
 
int main(){
    ll n,t,V;
    scanf("%lld%lld%lld",&n,&t,&V);
    for(ll i=1;i<=n;i++){
        ll a,b,c;
        scanf("%lld%lld%lld",&a,&b,&c);
        w[i]=a+c;
        v[i]=b;
    }
    f[0][0]=1;
    for(ll i=0;i<=t;i++){
        for(ll j=0;j<=V;j++){
            dp[i][j]=-1;
        }
    }
    dp[0][0]=0;
    for(ll i=1;i<=n;i++){
        for(ll j=t;j>=w[i];j--){
            for(ll k=V;k>=v[i];k--){
                if(dp[j-w[i]][k-v[i]]>=0){
                    if(dp[j-w[i]][k-v[i]]+1 >dp[j][k]){
                        dp[j][k]= dp[j-w[i]][k-v[i]]+1;
                        f[j][k]=f[j-w[i]][k-v[i]]%mod;
                    }
                    else if(dp[j-w[i]][k-v[i]]+1==dp[j][k]){
                        f[j][k]=(f[j][k]+f[j-w[i]][k-v[i]])%mod;
                    }
                }
            }
        }
    }
    ll maxx=0,maxnum=0;
    for(ll i=0;i<=t;i++){
        for(ll j=0;j<=V;j++){
            if(dp[i][j]>maxx){
                maxx=dp[i][j];
                maxnum=f[i][j];
            }else if(dp[i][j]==maxx){
                maxnum=(maxnum+f[i][j])%mod;
            }
        }
    }
    printf("%lld %lld\n",maxx,maxnum);
    return 0;
}

d.给n个数,问有多少个连续的区间和是k的倍数,

前缀问题,维护每个余数在前缀中出现的次数即可

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>
 
using namespace std;
 
const int maxn=1e6+10;
typedef long long ll;
 
ll a[maxn];
ll b[maxn];
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    ll num=0;
    ll sum=0;
    b[0]=1;
    for (int i=0;i<n;i++  ){
        scanf("%lld",&a[i]);
        sum+=a[i];
        sum=sum%k;
        num+=b[sum];
        b[sum]++;
    }
    printf("%lld\n",num);
    return 0;
}

e.给一个n和k,x=kkkkkkk....n个k,问x%1e9+7是多少(n<1e18,k<10

开始以为是找循环节,想着这个公式mod1e9+7循环节应该不是很长,写了个map发现炸了.......

解:

等比数列求和得到 :9x = q × (10n − 1)

设t = (M+1)/9 = 111111112

则 9t = M + 1 ≡ 1 (mod M) 两边乘以 x

则有 x ≡ 9tx = t × 9x = t × q × (10n − 1) (mod M)

因此算 t × q × (10n − 1) 就行了

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
const int mod=1e9+7;

const ll t=111111112;

ll n,k;

ll pow2(ll a,ll n){
    if(n==0)return 1;
    ll x=pow2(a,n/2);
    ll ans=x*x%mod;
    if(n%2==1)ans=ans*a%mod;
    return ans;
}

int main(){
    scanf("%lld%lld",&n,&k);
    ll num=(t*(k*(pow2(10LL,n)-1+mod)%mod)%mod)%mod;
    printf("%lld\n",num);
    return 0;
}

f.给一个分数的中缀表达式,求结果(分数形式的结果)

大模拟(分数类+中缀表达式转后缀表达式+计算后缀表达式)

g.把一个数组分成连续的任意段,每一段所有数异或之后相等

两种情况:1,全部数字异或之后为0,随便找个点分开即可。

2,全部数字异或不为0后,设异或和为num,那么分完后结果必然是奇数段,且每一段异或和为num,那么直接分成三段,找第一次前缀异或为num的地方,和再次之后异或为0的地方即可

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
const int maxn=1e6+10;
int a[maxn],n;

int main(){
    scanf("%d",&n);
    int num=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        num=num^a[i];
    }
    if(n<2){
        printf("-1\n");
        return 0;
    }
    if(num==0){
        printf("2\n");
        printf("1");
    }else{
        int l=0,r=0;
        int num0=0;
        for(int i=1;i<=n;i++){
            num0=num0^a[i];
            if(num0==num && l==0){
                l=i;
            }
            else if(l>0 && num0==0){
                r=i;
            }
        }
        if(l>0&&r>l){
            printf("3\n");
            printf("%d %d",l,r);
        }else{
            printf("-1");
        }
    }
    return 0;
}

h.比较有意思的一道题,是luogu p1362原题

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>
 
using namespace std;
typedef long long ll;
const int maxn=30000;
int l,r,cnt,anss;
int ans[30000];
 
void build(int x,int y,int z){
    ll a=x;
    a=a*a;
    int b=0;
    if(x>=l&&x<=r){
        while(a){
            b+=a%10;
            a/=10;
        }
        if(y*y==b)
            ans[++cnt]=x;
    }
    if(z>r) return;
    for(int i=0;i<4;i++)
        build(x*10+i,y+i,z*10);
}
 
int main(){
    scanf("%d%d",&l,&r);
    build(0,0,1);
    sort(ans+1,ans+1+cnt);
    for(int i=1;i<=cnt;i++){
        if(ans[i-1]!=ans[i])
            anss++;
    }
    printf("%d",anss);
    return 0;
}

 i.给你一棵有根树,树上有n个节点,m个节点上有人,人在树上的代价是他的深度,每个人只可以往自己的父亲节点走,并且每个节点上只可以站一个人,问最小代价是多少

用左偏树(可合并堆)维护每个子树的最小代价代价即可。

看了题解说dfs序+线段树也可以。

可合并堆代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#include <map>
#include <set>

using namespace std;

typedef long long ll;
const int mod=1e9+7;

const int maxn=5e5+10;
const int maxm=2*maxn;

//可合并堆部分
int tot,v[maxn],l[maxn],r[maxn],d[maxn];

int Mergr(int x,int y){
    if(!x)return (y);
    if(!y)return (x);


    if(v[x]<v[y])swap(x,y);
    r[x]=Mergr(r[x],y);
    if(d[l[x]]<d[r[x]])swap(l[x],r[x]);


    d[x]=d[r[x]]+1;
    return (x);
}

int Init(int x){
    tot++;
    v[tot]=x;
    l[tot]=r[tot]=d[tot]=0;
    return tot;
}

int Insert(int x,int y){
    return Mergr(x,Init(y));
}

int Top(int x){
    return (v[x]);
}

int Pop(int x){
    return Mergr(l[x],r[x]);
}


//树上dfs部分
int n,k;
int vis[maxn];
int vistot[maxn];
vector<int>edges[maxn];

void addedge(int u,int v){
    edges[u].push_back(v);
}

int numm=0;

void dfs(int u,int fa,int deep){
    for(int i=0;i<(int)edges[u].size();i++){
        int v=edges[u][i];
        if(v!=fa){
            dfs(v,u,deep+1);
        }
    }
    vistot[u]=Init(deep);
    for(int i=0;i<(int)edges[u].size();i++){
        int v=edges[u][i];
        if(v!=fa){
            vistot[u]=Mergr(vistot[u],vistot[v]);
        }
    }
    if(vis[u]==0){
        vistot[u]=Pop(vistot[u]);
        numm++;
    }

}

int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    for(int i=0;i<k;i++){
        int x;
        scanf("%d",&x);
        vis[x]=1;
    }
    dfs(1,0,0);
    int num=0;
    for(int i=numm;i<n;i++){
        num+=Top(vistot[1]);
        vistot[1]=Pop(vistot[1]);
    }
    printf("%d\n",num);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wz-archer/p/11942506.html