校内的训练赛,5小时做了6题,先把这6题放上来吧,之后补了题再来更新Σ(゚д゚;)
Kattis pieceofcake2 Piece of Cake!
题意简述:一块 n*n*4 的蛋糕被切横竖了两刀,距边缘分别为 h 和 v ,求最大的一块蛋糕大小。
暴力判断哪边更大即可
时间复杂度 O(1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> //#include <cstring> using namespace std; typedef long long ll; int main(){ ll b,x,y; scanf("%lld%lld%lld",&b,&x,&y); printf("%lld\n",max(x,b-x)*max(y,b-y)*4); return 0; }
Kattis fantasydraft Fantasy Draft
题意简述:有一群队员和一群老板,要组成几支队伍,每轮中每个老板依次选一个人。老板有一个偏好列表,总是会选择自己偏好列表中最靠前的人,否则就选择总排名最靠前的人,问最终的分配结果。
模拟题,我是先将所有人按名字排序,然后每轮将当前偏好度最大的人移出列表,二分查找这个人,再判断他是否已被选走,没选走就选这个人,把他的名次存到自己的 vector 里面,顺手给这个名次打个标记,偏好列表为空的时候再在之前存标记的数组里面顺序寻找没打标记的名次。最后重新按名次排序,输出名字。
两轮排序都是 O(plogp),中间二分查找 O(logp), 选人需要 O(n*m),又 n*m<p,因此总时间复杂度 O(plogp)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <string> #include <algorithm> #include <vector> using namespace std; typedef long long ll; struct player { string name; int rank; } arr[65010],temp; bool operator<(player a, player b) { return a.name<b.name; } bool cmp(player a,player b){ return a.rank<b.rank; } int chosen[65010],aptr; vector<string> preflist[70]; int prefptr[70]; int finalist[70][1010]; int main(){ int n,m,p; string str; cin>>n>>m; for(int i=0;i<n;i++){ int k; cin>>k; for(int j=0;j<k;j++) { cin>>str; preflist[i].push_back(str); } } cin>>p; for(int i=0;i<p;i++){ cin>>arr[i].name; arr[i].rank=i; } sort(arr,arr+p); for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ for(;prefptr[j]<preflist[j].size();prefptr[j]++){ temp.name=preflist[j][prefptr[j]]; int loc=lower_bound(arr,arr+p,temp)-arr; if(!chosen[arr[loc].rank]){ chosen[arr[loc].rank]=true; finalist[j][i]=arr[loc].rank; ++prefptr[j]; goto nextloop; } } for(;;aptr++){ if(!chosen[aptr]){ chosen[aptr]=true; finalist[j][i]=aptr; ++aptr; break; } } nextloop:; } } sort(arr,arr+p,cmp); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cout<<arr[finalist[i][j]].name<<(j==m-1?'\n':' '); } } return 0; }
Kattis foldingacube Folding a Cube
题意简述:给出一个形状,问这个形状能不能被折叠成正方体。
先考虑将这个形状放在一个平面上,指定一个块固定在这个平面上,然后折其他的部分来形成正方体。很容易得出结论:如果在平面的某侧能折出正方体,那么在另一侧也一定能折出。
这样我们不妨固定某一侧,想像将这个形状放在桌面上,在桌面上方折出这个正方体。
此时,形状朝上的部分总会在正方体的里面。用 UDLRFB 分别表示上下左右前后,我们看几个例子
.#. LD# .#.
在这么一部分中,我们不难确定上面的是 B 面,下面的是 F 面,右边的是 R 面。
同样的
.L. #D# .#.
在这么一部分中,我们也很好确定右边的是 B 面,左面的是 F 面,下面的是 R 面。
然后我们就可以发现,在这个形状中,如果知道某一块将作为哪个面,且知道它周围的某一块将作为哪个面,那么与这一块相邻的块都能确定将作为哪个面,它们之间的相对位置关系都是确定的。
感觉讲的有点抽象啊,不管怎么说,这样就可以用 dfs 解决了。
时间复杂度 O(n),n=6
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> //#include <cstring> using namespace std; typedef long long ll; const int U=0,D=1,L=2,R=3,F=4,B=5; const char symbols[]="UDLRFB"; char graph[6][10]; void printall(){ for(int i=0;i<6;i++){ for(int j=0;j<6;j++){ printf("%c",graph[i][j]<6?symbols[graph[i][j]]:graph[i][j]); } printf("\n"); } printf("\n"); } const int dirs[6][4]={ {F,R,B,L}, {F,L,B,R}, {U,B,D,F}, {U,F,D,B}, {U,L,D,R}, {U,R,D,L} }; const int rots[4][2]={ {0,1},{1,0},{0,-1},{-1,0} }; bool used[10]; const int rev[4]={2,3,0,1}; bool dfs(int ii,int jj,int from){ //printf("dfs %d %d\n",ii,jj); int dirofs=0,rotofs=0; if(from!=-1){ int oi=ii+rots[rev[from]][0],oj=jj+rots[rev[from]][1]; rotofs=rev[from]; for(;dirs[graph[ii][jj]][dirofs]!=graph[oi][oj];dirofs++); } for(int i=0;i<4;i++){ int ti=ii+rots[i][0],tj=jj+rots[i][1]; if(ti>=0&&tj>=0&&ti<6&&tj<6&&graph[ti][tj]=='#'){ int res=dirs[graph[ii][jj]][(dirofs-rotofs+4+i)%4]; if(used[res]) return false; used[res]=true; graph[ti][tj]=res; //printall(); if(!dfs(ti,tj,i)) return false; } } return true; } int main(){ for(int i=0;i<6;i++) scanf("%s",graph[i]); for(int i=0;i<6;i++){ for(int j=0;j<6;j++){ if(graph[i][j]=='#'){ graph[i][j]=D; used[D]=true; printf(dfs(i,j,-1)?"can fold\n":"cannot fold\n"); return 0; } } } return 0; }
Kattis integerdivision Integer Division
题意简述:给出除数和一堆被除数,问有多少对被除数除法运算结果的整数部分相同。
排个序扫一遍,然后依次算除法结果,发现和上一个不同的就把前面这一块相同的算出有多少对,把所有块结果加起来就行了
时间复杂度 O(nlogn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> //#include <cstring> using namespace std; typedef long long ll; int arr[200010]; int main(){ int d,n,c=1; ll ans=0; scanf("%d%d",&n,&d); for(int i=0;i<n;i++) scanf("%d",&arr[i]); sort(arr,arr+n); for(int i=1;i<n;i++){ if(arr[i]/d!=arr[i-1]/d){ ans+=ll(c)*ll(c-1)/2; c=1; } else ++c; } ans+=ll(c)*ll(c-1)/2; printf("%lld\n",ans); return 0; }
Kattis hogwarts2 Hogwarts
Kattis molecules Molecules
Kattis typo Typo
Kattis biggesttriangle The Biggest Triangle
Kattis tiredterry Tired Terry
题意简述:Terry 有一个睡眠模式周期,如果他之前 p 秒没有睡够 d 秒就会觉得很累,问他一个周期里面会有几秒很累。
先把前 p 秒的模式复制到最后一份,然后把前 p 秒睡觉时间记录下来,然后就像一个队列一样,记录下一秒有没有睡,去掉最前面一秒的睡眠,然后看当前累不累。
写代码的时候很困,把 p 和 d 写反了
时间复杂度 O(n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; char pat[200010]; int main(){ int l,p,d,zc=0,ans=0; scanf("%d%d%d%s",&l,&d,&p,pat); for(int i=0;i<d;i++){ if(pat[i]=='Z') zc++; pat[i+l]=pat[i]; } l+=d; for(int i=d;i<l;i++){ if(zc<p) ans++; if(pat[i]=='Z') ++zc; if(pat[i-d]=='Z') --zc; } printf("%d\n",ans); return 0; }
Kattis watchlater Watch Later
Kattis lostlineup Lost Lineup
题意简述:在一个队列里,知道每个人和第一个人之间有多少人,求这个队列。
排序完事
时间复杂度 O(nlogn)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> //#include <cstring> using namespace std; typedef long long ll; struct pe { int id,qd; } arr[110]; bool cmp(pe a,pe b){ return a.qd<b.qd; } int main(){ int n; scanf("%d",&n); for(int i=0;i<n-1;i++){ arr[i].id=i+2; scanf("%d",&arr[i].qd); } sort(arr,arr+n-1,cmp); printf("1"); for(int i=0;i<n-1;i++){ printf(" %d",arr[i].id); } printf("\n"); return 0; }