小米 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; }
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; }
#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; }
矩阵快速幂代码:
#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; }
It is your time to fight!