【题解】河南理工大学新生挑战赛

A、Dong Zhi

直接输出即可。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    printf("Let's eat dumplings");
    return 0;
}

B、The flower

利用储存长为的字符串,暴力计算即可。

#include<bits/stdc++.h>

using namespace std;
int main(){
    string s;
    int k;
    cin>>s>>k;
    unordered_map<string,int> mmp;
    set<string> st;
    int n=(int)s.length();
    for(int i=k-1;i<n;i++){
        string now=s.substr(i-(k-1),k);
        mmp[now]++;
        st.insert(now);
    }
    set<string> ans;
    for(auto v:st){
        if(mmp[v]>2){
             ans.insert(v);
        }
    }
    cout<<(int)ans.size()<<endl;
    for(auto v:ans) cout<<v<<endl;
    return 0;
} 

C、Xor Path

计算从根节点到每个节点的异或和,同时计算倍增。然后利用倍增可以实现的查询。

#include<bits/stdc++.h>

using namespace std;
const int N = 1e6+100;
vector<int> G[N];
int pre[N],a[N],par[N];
long long bit[30];
int f[N][30];
int depth[N];
void init(){
    bit[0]=1;
    for(int i=1;i<=29;i++) bit[i]=(bit[i-1]<<1);
}
void dfs(int u,int par){
    depth[u]=depth[par]+1;
    f[u][0]=par;
    for(int i=1;bit[i]<=depth[u];i++) f[u][i]=f[f[u][i-1]][i-1];
    for(int v:G[u]){
        if(v!=par) dfs(v,u);
    }
}
int lca(int x,int y){
    if(depth[x]<depth[y]) swap(x,y);
    for(int i=29;i>=0;i--){
        if(depth[x]-depth[y]>=bit[i]){
            x=f[x][i];
        }
    }
    if(x==y) return x;
    for(int i=29;i>=0;i--){
        if(depth[x]>=(1<<i)&&f[x][i]!=f[y][i]){
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}
void DFS1(int u,int fa){
    par[u]=fa;
    pre[u]=pre[fa]^a[u];
    for(int v:G[u]){
        if(v==fa) continue;
        DFS1(v,u);
    }
}
int main(){
    int n,u,v,q;
    cin>>n;
    init();
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=0;i<=n;i++) G[i].clear();
    for(int i=1;i<=n-1;i++){
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0);
    DFS1(1,0);
    int x,y;
    cin>>q;
    while(q--){
        cin>>x>>y;
        int c=lca(x,y);
        int f=par[c];
        cout<<(pre[x]^pre[f]^pre[c]^pre[y])<<endl;
    }
    return 0;
}

D、LaunchPad

开两个数组分别记录当前行或列是否有操作,再开一个二维数组计算每个灯在操作后的亮灭情况(用来调整行和列所带来的一次操作而不是两次操作)。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1000+10;
int a[maxn],b[maxn];
int c[maxn][maxn];
int main()
{
    int n,m,q;
    scanf("%d %d",&n,&m);
    scanf("%d",&q);
    while(q--){
        int u,v;
        scanf("%d %d",&u,&v);
        c[u][v]^=1;
        a[u]^=1;
        b[v]^=1;
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            ans+=a[i]^b[j]^c[i][j];
        }
    }
    printf("%d\n",ans);
    return 0;
}

E、Morse code

长度为种情况已经全部出现过,长度为种情况也已经出现过,因此我们一定能够利用长度为的字母去填充,因此答案就是

此处给出做法,以供学习。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
map<int,int>mp;
string code[100];
char s[maxn];
int dp[maxn];
void init(){
    code[1]=".-";   code[2]="-..."; code[3]="-.-."; code[4]="-..";
    code[5]="..-."; code[6]="--.";  code[7]="....";
    code[8]="..";   code[9]=".---"; code[10]="-.-"; code[11]=".-..";
    code[12]="--";  code[13]="-.";  code[14]="---"; code[15]=".--.";
    code[16]="--.-";code[17]=".-."; code[18]="...";
    code[19]="..-"; code[20]="...-"; code[21]=".--";code[22]="-..-";
    code[23]="-.--"; code[24]="--..";
    for(int i=1;i<=24;i++){
        int num=0;
        for(int j=0;j<code[i].length();j++) num=num*100+code[i][j];
        mp[num]++;
    }
}
int cal(int a,int b){
    int num=0;
    for(int i=a;i<=b;i++) num=num*100+s[i];
    return mp[num]?1:0;
}
void solve(){
    scanf("%s",s);
    int n=strlen(s);
    for(int i=0;i<n;i++){
        dp[i]=0;
        for(int j=1;j<=4;j++){
            int y=i-j;
            dp[i]=max(dp[i],dp[i-j]+cal(i-j+1,i));
        }
    }
    printf("%d\n",dp[n-1]);
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--){
        solve();
    }
    return 0;
}

F、Puzzle

原签到题。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<ll,ll>
const ll maxn=1000000+10;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
int a[100];
void init(){
    a[0]=1;
    a[1]=0;
    a[2]=0;
    a[3]=0;
    a[4]=1;
    a[5]=0;
    a[6]=1;
    a[7]=0;
    a[8]=2;
    a[9]=1;
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--){
        ll x;
        scanf("%lld",&x);
        if(x==0) printf("1\n");
        else{
            int num=0;
            while(x){
                num+=a[x%10];
                x/=10;
            }
            printf("%d\n",num);
        }
    }
    return 0;
}

G、Triangle tower

尖向上的小三角形能够组成一个杨辉三角,向下的又能够组成一个杨辉三角,因此分情况计算即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
const int maxn=100000+10;
ll fac[maxn];
void init(){
    fac[0]=1;
    for(int i=1;i<=maxn;i++) fac[i]=fac[i-1]*i%mod;
}
ll qp(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll c(int n,int m){
    return fac[n]*qp(fac[m],mod-2)%mod*qp(fac[n-m],mod-2)%mod;
}
ll solve(int n,int m){
    n--;
    if(m%2==0) n--;
    m=(m-1)/2;
    printf("%lld\n",c(n,m));
}
int main()
{
    int t,n,m;
    scanf("%d",&t);
    init();
    while(t--){
        scanf("%d %d",&n,&m);
        solve(n,m);
    }
    return 0;
}

H、Kingdom of Mathematics

应该是整个比赛里面最难的一个题?

Part1
$g(x)=f(x)+x$
Part2

可以发现,的二进制表示位数为位,而且在足够大时,可以发现高位数几乎全为。我们将每两项进行异或,可以发现 ,因此前偶数项我们就可以用类似的方法计算出结果 ,结果为各项部分相加,最后一位判断总共有多少对即可。

对于奇数,我们已知前位的值,我们将其分为两部分,低位部分位影响到的部分(即与高位全一部分的分界线),高位部分为全一部分。然后分开计算即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1000000+10;
const ll mod=1e9+7;
ll T,n;
ll qp(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
//等比数列前x项之和 第一项为1 
ll judge(ll x){
    ll sum=(qp(4,x)-1+mod)%mod;
    return 2*sum*qp(3,mod-2)%mod;
}
//二进制位数 
ll bits(ll x){
    ll sum=0;
    while(x){
        sum++;
        x>>=1;
    }
    return sum;
}
ll revise(ll x,ll step){
    ll pos=1;
    stack<ll>st;
    for(int i=1;i<=step;i++){
        if(i%2==0) st.push(1-(x&1));
        else st.push(x&1);
        x>>=1;
    }
    ll sum=0;
    while(!st.empty()){
        sum=sum*2+st.top();
        st.pop();
    }
    return sum;
}
int main()
{
    scanf("%lld",&T);
    while(T--){
        ll res;
        scanf("%lld",&n);
        if(n&1){
            ll vis=bits(n);
            //高位没被影响到的的值
            res=judge((n-vis)/2);
            if((n-vis)&1) res=(res*2+1)%mod;
            res=res*qp(2,vis)%mod;
            //低位被异或的值
            res=(res+revise((1ll<<vis)-n,vis))%mod;

            //最后一位加or减 
            if((n/2)&1){
                if(n&1) res=(res-1+mod)%mod;
                else res=(res+1)%mod;
            }
        }
        else{
            res=judge(n/2);
            if((n/2)&1) res=(res+1)%mod;
        }
        printf("%lld\n",res);
    }
    return 0;
}

I、HPU's birthday

暴力计算每个的贡献即可,假如某个前面有,那么它的贡献即为

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
int q[100];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        int num=0;
        ll ans=0;
        ll x=n;
        while(x){
            q[num++]=x&1;
            x>>=1;
        }
        x=0;
        for(int i=0;i<n;i++){
            for(int j=num-1;j>=0;j--){
                if(q[j]) x++;
                else ans=(ans+x*(x-1)/2)%mod;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

以下为的解法:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
int q[100];
ll qp(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll cal(ll x,ll n,ll a){
    ll ans=0;
    ans=n*x*x%mod;
    ans=(ans+(n-1)%mod*n%mod*x%mod*a%mod);
    ans=(ans+(n-1)%mod*n%mod*(2*n-1)%mod*qp(2,mod-2)%mod*a%mod*a%mod);
    ans=(ans-n%mod*x%mod+mod)%mod;
    ans=(ans-(n-1)%mod*n%mod*qp(2,mod-2)%mod*a%mod+mod)%mod;
    return ans;
}
int main()
{
    ll inv2=qp(2,mod-2);
    ll t;
    scanf("%lld",&t);
    while(t--){
        ll n;
        scanf("%lld",&n);
        ll num=0,ans=0,x=n;
        ll one=0;
        while(x){
            if(x&1) one++;
            q[num++]=x&1;
            x>>=1;
        }
        x=0;
        for(int i=num-1;i>=0;i--){
            if(q[i]) x++;
            else ans=(ans+cal(x,n,one)); 
        }
        printf("%lld\n",ans*inv2%mod);
    }
    return 0;
}

J、Max Sum

我们首先记录前缀和数组和后缀和数组,然后对其建两棵线段树。

对于第个位置,我们计算区间的最小前缀和和的最小后缀和,数组总和减去这两部分的值即为第个位置的最大值。由于数据范围的原因,还要特别处理一下边界条件。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1000000+10;
const int INF=0x3f3f3f3f;
int a[maxn];
ll pre[maxn],nxt[maxn];
int k[maxn];
int N;
struct Tree{
    ll x[maxn];
    void init(int x){
        N=1;
        while(N<=x*2) N*=2;
    }
    void update(int k,int q){
        k+=N-1;
        x[k]=q;
        while(k){
            k=(k-1)/2;
            x[k]=min(x[k*2+1],x[k*2+2]);
        }
    }
    ll query(int a,int b,int l,int r,int k){
        if(r<a || b<l) return INF;
        if(a<=l && r<=b) return x[k];
        else{
            ll vl=query(a,b,l,(l+r)/2,k*2+1);
            ll vr=query(a,b,(l+r)/2+1,r,k*2+2);
            return min(vl,vr);
        }
    }
}tp,tn;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&k[i]);
    tp.init(n);
    ll sum=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum+=a[i];
        tp.update(i,sum);
    }
    sum=0;
    for(int i=n;i>=1;i--){
        sum+=a[i];
        tn.update(i,sum);
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        ans+=sum;
        ans-=tp.query(max(i-k[i]-1,0),max(i-1,0),0,N-1,0);
        ans-=tn.query(min(i+1,n+1),min(i+k[i]+1,n+1),0,N-1,0);
    }
    printf("%lld\n",ans);
    return 0;
}

K、Restore Expressions

要使中的贡献最小,首先把除了第一项以外的值全部置为,仅考虑第一项的值即可,假设表达式的值为,计算出两个式子第一项值为,那么我们就进行如下操作:若其中一项不为正数,则两个数均加上一个值使得两个数均为正数。这样可以使得两个式子值相同且贡献尽可能的小。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2000000+10;
char s[maxn],t[maxn];
void solve(){
    int n;
    scanf("%d",&n);
    scanf("%s %s",s,t);
    int a=0,b=0;
    for(int i=0;i<n;i++){
        if(s[i]=='-') a++;
        else a--;
        if(t[i]=='-') b++;
        else b--;
    }
    int prea,preb;
    prea=a+max(1-min(a,b),0);
    preb=b+max(1-min(a,b),0);

    printf("%d %d\n",0,prea+preb+n*2);

    printf("%d",prea);
    for(int i=1;i<=n;i++) printf(" %d",1);
    printf("\n");

    printf("%d",preb);
    for(int i=1;i<=n;i++) printf(" %d",1);
    printf("\n");
}
int main()
{
    solve();
    return 0;
}
全部评论

相关推荐

点赞 评论 收藏
分享
8 收藏 评论
分享
牛客网
牛客企业服务