比赛:2018年长沙理工大学第十三届程序设计竞赛
形式:团队赛
队伍出题:9/12
个人出题:4
A:不分大小写,判断一个字符串是否是lovelive。 注意字符串可能包含空格
E:求最短路。spfa模板。
F:经过推理,正确的推理出了题目就是要求组合数C(x-1,i)的和×p%mod,其中0<=i<=min(x,y)。无奈没预处理逆元,导致O(logn)的复杂度TLE。赛后补过。。。贴上代码:
#include<bits/stdc++.h> #define lson l,mid,t<<1 #define rson mid+1,r,t<<1|1 #define ll long long using namespace std; const int maxn=1000010; const long long mod=1e9+7; int n,m,q,k,flag,x,f,y,p; long long ni[maxn]; long long a[maxn]; long long zuhe(int x,int y){ return a[x]*ni[y]%mod*ni[x-y]%mod; } long long calc(long long x,long long y){ long long z=1; while (y){ if (y&1)(z*=x)%=mod; (x*=x)%=mod,y/=2; } return z; } int main() { ios::sync_with_stdio(false); a[0]=1; for (int i=1;i<maxn;i++)a[i]=a[i-1]*i%mod; ni[maxn-1]=calc(a[maxn-1],mod-2); for (int i=maxn-2;i>=0;i--)ni[i]=ni[i+1]*(i+1)%mod; while(cin>>m>>x>>y>>p) { x--; long long ans=0; for(int i=0;i<=min(x,y);i++) { ans+=zuhe(x,i); } cout<<ans%mod*p%mod<<endl; } return 0; }
G:从起点出发,拿到任意一把钥匙后即可走入出口所在的格子,用两遍bfs。先给每个有钥匙的格子编号记录,第一遍bfs求从起点到每个钥匙的最短距离,第二遍dfs求终点到每把钥匙的距离,和取个最小值即可。刚开始我是从每把钥匙开始bfs终点,然后蜜汁TLE。。。后来经过小伙伴提示,成功AC。
代码:
#pragma comment(linker,"/STACK:102400000,102400000") #include<bits/stdc++.h> #define lson l,mid,t<<1 #define rson mid+1,r,t<<1|1 #define ll long long using namespace std; const int maxn=510; char s[maxn][maxn]; int n,m,q,k,flag,x,f; int us[maxn][maxn],idd[maxn][maxn]; int ans[maxn*maxn],tmp,cnt,anss; bool b[maxn][maxn]; int disk[maxn*maxn],dise[maxn*maxn]; int mi; int dxy[]={0,1,0,-1,1,0,-1,0}; struct node { int x,y; int id; int num; node(){num=0;} node(int xx,int yy,int dd){x=xx;y=yy;id=dd;num=0;} }a[maxn],sta,ed; void solve() { memset(b,0,sizeof(b)); queue<node>q; ed.id=-1; ed.num=0; q.push(ed); b[ed.x][ed.y]=1; while(!q.empty()) { node k=q.front();q.pop(); if(k.num>=anss) continue; if(idd[k.x][k.y]!=-1) { anss=min(anss,a[idd[k.x][k.y]].num+k.num); } node t; for(int i=0;i<4;i++) { int xx=k.x+dxy[i]; int yy=k.y+dxy[i+4]; if(xx>=0&&xx<n&&yy>=0&&yy<m&&s[xx][yy]!='#'&&!b[xx][yy]) { t=node(xx,yy,k.id); t.num=k.num+1; { b[xx][yy]=1; q.push(t); } } } } } void solve2() { memset(b,0,sizeof(b)); queue<node>q; sta.id=-1; q.push(sta); b[sta.x][sta.y]=1; while(!q.empty()) { node k=q.front();q.pop(); if(idd[k.x][k.y]!=-1) { if(disk[idd[k.x][k.y]]==5000) {disk[idd[k.x][k.y]]=k.num; k.id=1; a[idd[k.x][k.y]].num=k.num; } } node t; for(int i=0;i<4;i++) { int xx=k.x+dxy[i]; int yy=k.y+dxy[i+4]; if(xx>=0&&xx<n&&yy>=0&&yy<m&&s[xx][yy]!='#'&&!b[xx][yy]) { if(s[xx][yy]!='E'||(s[xx][yy]=='E'&&k.id>0)){ t=node(xx,yy,k.id); t.num=k.num+1; { b[xx][yy]=1; q.push(t); } } } } } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); //getchar(); f=0; memset(idd,-1,sizeof(idd)); flag=1; for(int i=0;i<n;i++) scanf("%s",s[i]); for(int i=0;i<n;i++) for(int j=0;j<m;j++) { if(s[i][j]=='P') {sta.x=i;sta.y=j;sta.num=0;} if(s[i][j]=='E') {ed.x=i;ed.y=j;ed.num=0;} if(s[i][j]=='K') {a[f+1]=node(i,j,f+1); disk[f+1]=5000; dise[f+1]=5000; f++; idd[i][j]=f; } } if(f==0) puts("No solution"); else { anss=5000; for(int i=1;i<=f;i++) a[i].num=5000; solve2(); solve(); if(anss==5000) puts("No solution"); else printf("%d\n",anss); } // memset(c,0,sizeof(c)); //printf("%d\n",ans); //if(flag) puts("Yes");else puts("No"); } return 0; }
L:大笼子放两只,小笼子放一只,直接暴力即可,注意一个人若带了奇数个仓鼠但是没有小笼子了那就必须用一个大笼子。
另:K题是最小链覆盖。。。拆点dinic一下就出来了。。。比赛的时候没一个人过,也根本想不到。。。醉,看来我们还不够懂网络流深邃的思想。
总结:团队配合还算比较好。题目难度中下等,数学题挺多,也是考验了思维能力,细节比较多,知识点用的还少,就是F题没出有点可惜。K题最小割想不到。。。剩下那个一看就不会。。。还是看数学的队友比较给力,出了1道水题和3道数学题(膜拜)像我这样的也就出了4道水题。。。队长很给力的把属于他的DP过了。。。再加上这次比赛大佬比较少,一段时间甚至我们队排行第一(也是醉了),最后由于F题没出屈居第五,算一般发挥吧。明天比赛继续加油。
资料:
看了Przz博客里部分dp以及背包的内容,细看还真是有点头疼。(不得不承认我dp水平之低)各种背包和状态转移。。。看的有点迷。