小米 OJ 编程比赛 03 月常规赛

A.数学等式

数据比较小,可以暴力+折半枚举。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=200010;
map<int,int>mp;
int main()
{
    int N,A,B,C,D,E; ll ans=0;
    scanf("%d%d%d%d%d",&A,&B,&C,&D,&E);
    rep(i,-50,50)
     rep(j,-50,50)
      rep(k,-50,50){
        if(i*j*k==0) continue;
        int x=A*i*i*i+B*j*j*j+C*k*k*k;
        mp[x]++;
    }
    rep(i,-50,50)
     rep(j,-50,50){
       if(i*j==0) continue;
       int x=D*i*i*i+E*j*j*j;
       ans+=mp[x];
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

B.贪吃的细胞

最小生成树,即是S和所有的营养液连通,我们把S和营养液看成关键点,那么预处理出关键点之间的两两距离(BFS即可)。

然后从S开始,跑基于prim的最小生成树。 题中,我们需要加限制,即如果A->B要连边(A处一个细胞到B处),那么A的细胞数不能为0,而一个细胞跑到B后,变为c[B]+1个,同时用B到其他点的距离更新最小距离。

(由于std出了问题,我们先假设代码是对的。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=210;
const int inf=1000000;
char c[maxn][maxn];
int id[maxn][maxn],vis[maxn][maxn],X[maxn],Y[maxn],Z[maxn];
int T,N,M,tot,Sx,Sy,num;
int peo[maxn],used[maxn],Dis[maxn][maxn],ans;
int xx[4]={1,-1,0,0},yy[4]={0,0,1,-1};
int dis[maxn][maxn][maxn],qx[maxn*maxn],qy[maxn*maxn],head,tail;
struct in{
    int id,dis,from;
    in(){}
    in(int ii,int dd,int ff):id(ii),dis(dd),from(ff){}
    friend bool operator <(in w,in v){
        return w.dis>v.dis;
    }
};
priority_queue<in>q;
void dfs1(int x,int y)
{
    if(x<1||x>N||y<1||y>M||vis[x][y]||c[x][y]=='#') return ;
    vis[x][y]=1; if(c[x][y]>='1'&&c[x][y]<='9') num++;
    rep(i,0,3) dfs1(x+xx[i],y+yy[i]);
}
void get(int p) //得到关键点和其他关键点的距离
{
    rep(i,1,N) rep(j,1,M) dis[p][i][j]=inf;
    rep(i,1,tot) Dis[p][i]=inf;
    head=tail=0; head++;
    qx[head]=X[p],qy[head]=Y[p]; dis[p][X[p]][Y[p]]=0;
    while(tail<head){
        tail++;
        int tx=qx[tail],ty=qy[tail];
        rep(i,0,3){
            int rx=tx+xx[i],ry=ty+yy[i];
            if(rx>=1&&rx<=N&&ry>=1&&ry<=M&&c[rx][ry]!='#'&&dis[p][rx][ry]==inf){
                dis[p][rx][ry]=dis[p][tx][ty]+1;
                if(id[rx][ry]) Dis[p][id[rx][ry]]=dis[p][rx][ry];
                head++; qx[head]=rx; qy[head]=ry;
            }
        }
    }
}
void solve()
{
    rep(i,0,tot) get(i);
    rep(i,1,tot) peo[i]=used[i]=0;
    peo[0]=1; ans=0; int sz=0; used[0]=1;
    rep(i,1,tot) if(Dis[0][i]!=inf){
        q.push(in(i,Dis[0][i],0));  //sz++;
    }
    while(!q.empty()){  //每次贪心的找最小边
        in t=q.top(); q.pop();
        if(t.id&&peo[t.from]&&!used[t.id]){
            peo[t.from]--; used[t.id]=1; ans+=t.dis;
            peo[t.id]+=1+Z[t.id]; sz++;
            rep(i,1,tot) if(!used[i]&&Dis[t.id][i]!=inf){ //来源有多的细胞,且目的地没有被用掉,则合法
               q.push(in(i,Dis[t.id][i],t.id));
            }
        }
    }
}
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&M);
        rep(i,1,N) scanf("%s",c[i]+1);
        tot=num=0;
        rep(i,1,N) rep(j,1,M) id[i][j]=vis[i][j]=0;
        rep(i,1,N)
         rep(j,1,M){
             if(c[i][j]>='1'&&c[i][j]<='9') {
                id[i][j]=++tot;
                X[tot]=i; Y[tot]=j; Z[tot]=c[i][j]-'0';
             }
             else if(c[i][j]=='S'||c[i][j]=='s') X[0]=Sx=i,Y[0]=Sy=j;
        }
        dfs1(Sx,Sy);
        if(num!=tot){ puts("-1"); continue;}
        solve();
        printf("%d\n",ans);
    }
    return 0;
}
View Code

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=210;
const int inf=1000000;
char c[maxn][maxn];
int id[maxn][maxn],vis[maxn][maxn],X[maxn],Y[maxn],Z[maxn];
int T,N,M,tot,Sx,Sy,num;
int peo[maxn],used[maxn],Dis[maxn][maxn],ans;
int xx[4]={1,-1,0,0},yy[4]={0,0,1,-1};
int dis[maxn][maxn][maxn],qx[maxn*maxn],qy[maxn*maxn],head,tail;
struct in{
    int id,dis,from;
    in(){}
    in(int ii,int dd,int ff):id(ii),dis(dd),from(ff){}
    friend bool operator <(in w,in v){
        return w.dis>v.dis;
    }
};
priority_queue<in>q;
void dfs1(int x,int y)
{
    if(x<1||x>N||y<1||y>M||vis[x][y]||c[x][y]=='#') return ;
    vis[x][y]=1; if(c[x][y]>='1'&&c[x][y]<='9') num++;
    rep(i,0,3) dfs1(x+xx[i],y+yy[i]);
}
void get(int p)
{
    rep(i,1,N) rep(j,1,M) dis[p][i][j]=inf;
    rep(i,1,tot) Dis[p][i]=inf;
    head=tail=0; head++;
    qx[head]=X[p],qy[head]=Y[p]; dis[p][X[p]][Y[p]]=0;
    while(tail<head){
        tail++;
        int tx=qx[tail],ty=qy[tail];
        rep(i,0,3){
            int rx=tx+xx[i],ry=ty+yy[i];
            if(rx>=1&&rx<=N&&ry>=1&&ry<=M&&c[rx][ry]!='#'&&dis[p][rx][ry]==inf){
                dis[p][rx][ry]=dis[p][tx][ty]+1;
                if(id[rx][ry]) Dis[p][id[rx][ry]]=dis[p][rx][ry];
                head++; qx[head]=rx; qy[head]=ry;
            }
        }
    }
}
void solve()
{
    rep(i,0,tot) get(i);
    rep(i,1,tot) peo[i]=used[i]=0;
    peo[0]=1; ans=0; int sz=0; used[0]=1;
    rep(i,1,tot) if(Dis[0][i]!=inf){
        q.push(in(i,Dis[0][i],0));  //sz++;
    }
    while(!q.empty()){
        in t=q.top(); q.pop();
        if(t.id&&peo[t.from]&&!used[t.id]){
            peo[t.from]--; used[t.id]=1; ans+=t.dis;
            peo[t.id]+=1+Z[t.id]; sz++;
            rep(i,1,tot) if(!used[i]&&Dis[t.id][i]!=inf){
               q.push(in(i,Dis[t.id][i],t.id));
            }
        }
    }
}
int main()
{
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&M);
        rep(i,1,N) scanf("%s",c[i]+1);
        tot=num=0;
        rep(i,1,N) rep(j,1,M) id[i][j]=vis[i][j]=0;
        rep(i,1,N)
         rep(j,1,M){
             if(c[i][j]>='1'&&c[i][j]<='9') {
                id[i][j]=++tot;
                X[tot]=i; Y[tot]=j; Z[tot]=c[i][j]-'0';
             }
             else if(c[i][j]=='S'||c[i][j]=='s') X[0]=Sx=i,Y[0]=Sy=j;
        }
        dfs1(Sx,Sy);
        if(num!=tot){ puts("-1"); continue;}
        solve();
        printf("%d\n",ans);
    }
    return 0

C.小爱密码 2.0

一看就是规律题,打出前面几个,发现除了前面两个其他的下标都是素数,那么我们素数筛得到所有对应的fib下标即可。 然后针对问题,我们矩阵乘法得到对应的答案,然后exgcd求逆元。(m不是素数,不能快速幂求逆元。

打表代码:

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=7500010;
ll a[40];
int main()
{
    a[3]=2; a[4]=3;
    rep(i,5,30) a[i]=a[i-1]+a[i-2];
    rep(i,3,30){
        int f=0;
        rep(j,3,i-1) if(a[i]%a[j]==0) f=1;
        if(!f) cout<<i<<" ";
    }
    return 0;
}
View Code

矩阵快速幂代码:

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=7500010;
bool vis[maxn]; int p[500010],cnt,Mod;
void prime()
{
    for(int i=2;i<maxn;i++){
        if(!vis[i]){
            p[++cnt]=i;
            if(cnt==500000) break;
        }
        for(int j=1;j<=cnt&&i*p[j]<maxn;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
}
struct mat{
    int m[2][2];
    mat(){memset(m,0,sizeof(m));}
    friend mat operator *(mat a,mat b){
        mat res;
        rep(i,0,1)
         rep(j,0,1)
          rep(k,0,1) (res.m[i][j]+=1LL*a.m[i][k]*b.m[k][j]%Mod)%=Mod;
        return res;
    }
    friend mat operator ^(mat a,int x){
        mat res; res.m[0][0]=res.m[1][1]=1;
        while(x){
            if(x&1) res=res*a; a=a*a; x>>=1;
        } return res;
    }
};
int getfib(int N)
{
    mat ans,base;
    ans.m[0][0]=ans.m[1][0]=1;
    base.m[0][0]=base.m[0][1]=base.m[1][0]=1;
    ans=(base^(N-2))*ans;
    return ans.m[0][0];
}
void exgcd(int a,int b,int d,int &x,int &y)
{
    if(b==0){ d=a; x=1; y=0; return;}
    exgcd(b,a%b,d,y,x); y-=a/b*x;
}
int rev(int a,int b)
{
    int x,y,d;
    exgcd(a,b,d,x,y); return (x+b)%b;
}
int main()
{
    prime(); int N;
    p[1]=3; p[2]=4;
    while(~scanf("%d%d",&N,&Mod)){
        N=p[N];
        int ans=getfib(N);
        ans=1LL*ans*rev(3,Mod)%Mod;
        int L=0,x=ans;
        while(x){ x/=10; L++;}
        if(ans==0) L++;
        rep(i,1,9-L) putchar('*');
        printf("%d\n",ans);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/hua-dong/p/10625322.html