喵哈哈村的魔法考试 Round #17 题解

喵哈哈村的秘境探险系列。

A.

实际上就是求乘积%k是否等于0,显然 a * b % k = (a%k)*(b%k)%k,所以边乘边取模就好了。

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

int main(){
    long long n,k;
    while(cin>>n>>k){
    long long now = 1;
    for(int i=0;i<n;i++){
        long long x;
        cin>>x;
        now = now * x % k;
    }
    if(now == 0)
        cout<<"Yes"<<endl;
    else
        cout<<"No"<<endl;
    }
}

B.

异或是可以前缀和的,因为x^x=0,所以 答案就是sum[r]^sum[l-1]

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+7;
int q,sum[maxn],n,a[maxn];

int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    while(cin>>n){
        for(int i=1;i<=n;i++)
            cin>>a[i];
        for(int i=1;i<=n;i++)
            sum[i]=a[i]^sum[i-1];
        cin>>q;
        while(q--){
            int x,y;
            cin>>x>>y;
            cout<<(sum[y]^sum[x-1])<<endl;
        }
    }
}

C

不修改,是滑雪的经典题,就是一个记忆化搜搜。

第一个修改操作是O(1),剩下的每次O(n2)修改,然后O(n2)跑DP就好。。

#include <bits/stdc++.h>
using namespace std;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
int f[705][705],mark[705][705],m[705][705];
int n;
int S(int x,int y){
    if(mark[x][y])return 0;
    if(f[x][y])return f[x][y];
    f[x][y]=1;
    for(int i=0;i<4;++i){
        int _x=x+dx[i],_y=y+dy[i];
        if(_x>n||_y>n||_x<1||_y<1)continue;
        if(m[_x][_y]>=m[x][y])continue;
        f[x][y]=max(f[x][y],S(_x,_y)+1);
    }
    return f[x][y];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    for(int j=1;j<=n;++j){
        scanf("%d",&m[i][j]);
    }
    char opt[2];
    int m2,q,w,e,r;
    scanf("%d",&m2);
    for(int i=1;i<=m2;++i){
        scanf("%s",opt);
        if(opt[0]=='C'){
            scanf("%d%d%d",&q,&w,&e);
            m[q][w]=e;
        }
        else if(opt[0]=='S'){
            scanf("%d%d%d%d",&q,&w,&e,&r);
            for(int i=q;i<=e;++i)
            for(int j=w;j<=r;++j)
            mark[i][j]=1;
        }
        else if(opt[0]=='B'){
            scanf("%d%d%d%d",&q,&w,&e,&r);
            for(int i=q;i<=e;++i)
            for(int j=w;j<=r;++j)
            mark[i][j]=0;
        }
        else {
            int ans=0;
            memset(f,0,sizeof(f));
            for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j){
                ans=max(ans,S(i,j));
            }
            printf("%d\n",ans);
        }
    }
    
    return 0;
}

D

算法其实很简单,我们以二进制为10111001这个数为例

原数为:
10111001

如果我们不取第一个1,那么后面7位我们可以随意取:
0*******
如果我们取第一个,不取第二个,那么后面5位我们可以随意取:
100*****

以此类推……

这样一来,我们就不受原数n的限定了,对于*部分,我们只需用组合数算出放1个1,放2个1,放3个1……的种数(记得加上前面已经确定的数位)
这样以来,我们也就知道了每种1的个数对应数的总数,题中是为了求乘积,那么快速幂即可

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
const int L_N=65;
const LL MOD=10000007;
LL f[L_N][L_N][2],NUM;
int val[L_N],len;

LL pow(int d,LL k){
    if(k==0) return 1;
    LL t=pow(d,k/2);
    t=t*t%MOD;
    if(k%2) t=t*d%MOD;
    return t;
}

int main(){
    scanf("%lld",&NUM);
    
    while(NUM){
        val[++len]=NUM&1;
        NUM>>=1;
    }
    reverse(val+1,val+1+len);
    
    f[0][0][1]=1;
    for(int i=1;i<=len;i++){
        for(int j=0;j<=i;j++){
            f[i][j][0]+=f[i-1][j][0];
            if(val[i]) f[i][j][0]+=f[i-1][j][1];
            if(!val[i]) f[i][j][1]+=f[i-1][j][1];

            if(j){				
                f[i][j][0]+=f[i-1][j-1][0];
                if(val[i]) f[i][j][1]+=f[i-1][j-1][1];
            }
        }
    }

    LL ans=1;
    for(int i=1;i<L_N;i++){
        LL d=f[len][i][0]+f[len][i][1];
        ans=(ans*pow(i,d))%MOD;
    }
    
    printf("%lld\n",ans);
    
    return 0;
}

E

树状数组/线段树来维护每个数的和,便于快速查询sum

更新的话,就直接暴力更新即可,因为每个数最多更新log(n)次就会到达1或者0

然后我们用并查集维护一下,如果更新到了1,就指向下一个需要更新的值就好了,直接跳过该值。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
LL a[100005],c[100005];
int f[100005],n,m,op,l,r,t;
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
int update(int x,LL num){while(x<=n)c[x]+=num,x+=(x&-x);}
LL sum(int x){LL s=0;while(x)s+=c[x],x-=(x&-x);return s;}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)f[i]=i,scanf("%lld",&a[i]),update(i,a[i]);
    scanf("%d",&m); f[n+1]=n+1;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&op,&l,&r);
        if(l>r)swap(l,r);
        if(op==1)printf("%lld\n",(sum(r)-sum(l-1)));
        else for(int j=l;j<=r;update(j,(t=(int)sqrt(a[j]))-a[j]),a[j]=t,
        f[j]=(a[j]<=1)?j+1:j,j=(find(j)==j?j+1:f[j]));
    }
    return 0;
}
posted @ 2017-04-25 10:31  qscqesze  阅读(258)  评论(0编辑  收藏  举报