2018徐州邀请赛
题目链接: https://www.jisuanke.com/contest/1408
A题
模拟一个BFS,输出最后一轮(层)被搜索的点中坐标最小的,比较坑的是 K==N*M 需要特判
1 #include <bits/stdc++.h> 2 #define fst first 3 #define scd second 4 #define ingrid(x,y) (x)>=1&&(x)<=N&&(y)>=1&&(y)<=M 5 using namespace std; 6 typedef pair<int ,int > pii; 7 8 bool graph[2001][2001]; 9 queue< pii > Q; 10 int N,M; 11 int dx[4]={0,0,1,-1}; 12 int dy[4]={1,-1,0,0}; 13 14 pii getmin(pii a,pii b){ 15 if(a.fst!=b.fst) return a.fst<b.fst?a:b; 16 return a.scd<=b.scd?a:b; 17 } 18 19 int main(){ 20 while(~scanf("%d%d",&N,&M)){ 21 int K; 22 scanf("%d",&K); 23 pii ans; 24 memset(graph,false,sizeof(graph)); 25 while(!Q.empty()) Q.pop(); 26 for(int i=0;i<K;++i){ 27 pii tmp; 28 scanf("%d%d",&tmp.fst,&tmp.scd); 29 graph[tmp.fst][tmp.scd]=true; 30 Q.push(tmp); 31 ans=tmp; 32 } 33 if(K==N*M) { printf("%d %d\n",ans.fst,ans.scd);continue;} 34 int tot=0; 35 for(;;){ 36 if(tot==N*M) break; 37 pii mm=make_pair(N+1,M+1); 38 int cnt=Q.size(); 39 tot+=cnt; 40 while(cnt--){ 41 pii u=Q.front();Q.pop(); 42 int ux=u.fst,uy=u.scd; 43 for(int i=0;i<4;++i){ 44 int nx=ux+dx[i],ny=uy+dy[i]; 45 if(ingrid(nx,ny)&&graph[nx][ny]==false){ 46 pii tmp=make_pair(nx,ny); 47 graph[nx][ny]=true; 48 Q.push(tmp); 49 mm=getmin(mm,tmp); 50 } 51 } 52 } 53 if(Q.size()+tot==N*M) { 54 ans=mm; 55 break; 56 } 57 } 58 printf("%d %d\n",ans.fst,ans.scd); 59 } 60 return 0; 61 }
B题
元素为(1~N)的序列,问逆序对有K个时,有几种排列。
1
1 1
1 2 2 1
1 3 5 6 5 3 1
... ...
设逆序对个数 num(N,K)表示 长度为N,逆序对个数为K的排列组合个数,有递推式 num(N+1,K)=num(N,K)+num(N+1,K-1)-num(N,K-N-1) ;num(N,0)=1
//luogu有类似题目
此题比较坑的地方是卡内存,必须储存询问,离线用滚动数组计算递推式。间接排序是个好东西。
1 #include <bits/stdc++.h> 2 #define fst first 3 #define scd second 4 using namespace std; 5 6 typedef pair<int ,int > pii; 7 const int MOD=1e9+7; 8 int num[2][5001]; 9 int ans[5001]; 10 pii query[5001]; 11 int _id[5001]; 12 int tmpid; 13 void solve(){ 14 int cntid=1; 15 int cur=0; 16 for(int i=0;i<5000;++i){ 17 memset(num[cur^1],0,sizeof(num[cur^1])); 18 num[cur^1][0]=1; 19 int bound=i*(i+1)/2; 20 for(int j=1;j<=5000&&j<=bound;++j) 21 { 22 if(j-i-1>=0) num[cur^1][j]=((num[cur^1][j-1]+num[cur][j])%MOD-num[cur][j-i-1]+MOD)%MOD; 23 else num[cur^1][j]=(num[cur^1][j-1]+num[cur][j])%MOD; 24 } 25 cur^=1; 26 while(cntid<tmpid&&i+1==query[_id[cntid]].fst) { 27 int KK=query[_id[cntid]].scd; 28 ans[_id[cntid]]=num[cur][KK]; 29 cntid++;// Don't forget ! 30 } 31 } 32 } 33 34 int N,K; 35 36 bool cmp(int i,int j){ 37 pii a=query[i],b=query[j]; 38 if(a.fst!=b.fst)return a.fst<b.fst; 39 return a.scd<b.scd; 40 } 41 42 int main(){ 43 tmpid=1; 44 while(~scanf("%d%d",&N,&K)){ 45 _id[tmpid]=tmpid; 46 query[tmpid]=make_pair(N,K); 47 tmpid++; 48 } 49 sort(_id+1,_id+tmpid,cmp); 50 solve(); 51 for(int i=1;i<tmpid;++i){ 52 printf("%d\n",ans[i]); 53 } 54 return 0; 55 }
D题
了解题意后答案就是一系列组合数的积,可以将这一系列组合数的积,转化公式( ∑Ui)!/∏(Ui!)
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define fst first 4 #define scd second 5 typedef pair<int ,int > pii; 6 typedef long long ll; 7 8 const ll MOD=1e9+7; 9 10 ll F[1000000+6]; 11 ll ans; 12 13 void init(){ 14 F[1]=1;F[2]=2; 15 for(ll i=3;i<=1000000;++i) 16 F[i]=F[i-1]*i%MOD; 17 } 18 19 ll inv(ll a,ll m){ 20 if(a==1) return 1; 21 return inv(m%a,m)*(m-m/a)%m; 22 } 23 24 int tot; 25 int A[1000000+6]; 26 int main(){ 27 init(); 28 int N; 29 while(~scanf("%d",&N)){ 30 tot=0; 31 for(int i=0;i<N;++i) { 32 scanf("%d",&A[i]); 33 tot+=A[i]; 34 } 35 ans=F[tot]; 36 for(int i=0;i<N;++i) { 37 ans=ans*inv(F[A[i]],MOD)%MOD; 38 } 39 printf("%lld\n",ans); 40 } 41 return 0; 42 }
E题
终点拆成两个点, 推出公式即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 const ll MOD=1e9+7; 6 ll F[2048]; 7 8 void init(){ 9 F[0]=1;F[1]=1; 10 for(ll i=2;i<=2000;++i) 11 F[i]=F[i-1]*i%MOD; 12 return; 13 } 14 15 ll qpow(ll a,ll b,ll mod){ 16 ll ret=1ll%mod; 17 while(b){ 18 if(b&1ll) ret=ret*a%mod; 19 a=a*a%mod; 20 b>>=1; 21 } 22 return ret; 23 } 24 25 ll ex_gcd(ll a,ll b,ll& x,ll& y){ 26 if(a==0&&b==0) return -1; 27 if(b==0){ 28 x=1;y=0;return a; 29 } 30 ll d=ex_gcd(b,a%b,y,x); 31 y-=a/b*x; 32 return d; 33 } 34 35 ll inv( ll a,ll n){ 36 return qpow(a,n-2,n); 37 } 38 39 ll getC(int m,int n){ 40 if(n>m) return 0;//2 2 41 return F[m]*inv(F[n],MOD)%MOD*inv(F[m-n],MOD)%MOD; 42 } 43 44 int main(){ 45 init(); 46 int N,M; 47 while(~scanf("%d%d",&N,&M)){ 48 ll a=getC(M+N-4,N-2); 49 ll b=getC(M+N-4,N-1); 50 ll c=getC(M+N-4,M-1); 51 printf("%lld\n",(a*a%MOD-b*c%MOD+MOD)%MOD); 52 } 53 return 0; 54 }
I题
直接dp会TLE,后来想切成M天内的小dp,各段再大DP,优化了一点但还是TLE
正确做法应该用类似 矩阵快速幂 的方法 进行dp
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 6 ll mod=1e18; 7 int N,M; 8 struct Matrix{ 9 ll dat[101][101]; 10 struct Matrix operator * (struct Matrix &b)const { 11 struct Matrix ret; 12 for(int i=1;i<=M;++i) 13 for(int j=1;j<=M;++j) 14 ret.dat[i][j]=0; 15 for(int i=1;i<=M;++i) 16 for(int j=1;j<=M;++j) 17 for(int k=1;k<=M;++k){ 18 ret.dat[i][j]=max(ret.dat[i][j],this->dat[i][k]+b.dat[k][j]); 19 } 20 return ret; 21 } 22 }stt; 23 24 Matrix qPow(Matrix a,int n){ 25 Matrix ret; 26 memset(ret.dat,0,sizeof(ret.dat)); 27 while(n){ 28 if(n&1) ret=ret*a; 29 a=a*a; 30 n>>=1; 31 } 32 return ret; 33 } 34 35 int main(){ 36 while(~scanf("%d%d",&N,&M)){ 37 for(int i=1;i<=M;++i) 38 for(int j=1;j<=M;++j) 39 stt.dat[i][j]=0; 40 for(int i=1;i<=M;++i) 41 for(int j=1;j<=M;++j){ 42 scanf("%lld",&stt.dat[i][j]); 43 } 44 Matrix fnl=qPow(stt,N-1); 45 ll ans=-1ll; 46 for(int i=1;i<=M;++i) 47 for(int j=1;j<=M;++j){ 48 ans=max(ans,fnl.dat[i][j]); 49 } 50 printf("%lld\n",ans); 51 } 52 return 0; 53 }
To be continued !
posted on 2018-07-25 01:16 Emiya_Kiritsugu 阅读(486) 评论(0) 编辑 收藏 举报