A、 Permutation
题意:对于一个素数p,找到1-p-1的一种排列,使得每个排列的后一个数与前一个数的两倍或者三倍之间是关于p同余的关系。
思路:我们根据题意进行模拟,我们先把1放在第一个,然后我们找到满足要求的第二个数,也就是对前一个数乘2或乘3再modp,如果这个数还没被放进排列里面的话,那么就放进排列里面,如果找不到下一个数的话,那么就说明不存在这样的排列,输出-1.这里我是用一个栈和一个队列来进行模拟的。
代码:
#include<iostream> #include<cstring> #include<algorithm> #include<stack> #include<queue> using namespace std; bool inq[1000010]; int main(){ int t; cin>>t; while(t--){ stack<int> st; queue<int> q; memset(inq,false,sizeof(inq)); int p; cin>>p; st.push(1); q.push(1); inq[1]=true; bool flag=true; while(1){ if(st.size()==p-1) break; int tmp=st.top(); int tmp1=2*tmp%p,tmp2=3*tmp%p; // cout<<"tmp1:"<<tmp1<<"tmp2:"<<tmp2<<endl; if(inq[tmp1]==false){ st.push(tmp1); q.push(tmp1); inq[tmp1]=true; } else if(inq[tmp2]==false){ st.push(tmp2); q.push(tmp2); inq[tmp2]=true; } else{ flag=false; break; } } if(!flag) cout<<"-1"<<endl; else{ while(!q.empty()){ cout<<q.front()<<" "; q.pop(); } cout<<endl; } } return 0; }
D、Hearthstone Battlegrounds
题意:这个题目太太太太太太长了,比赛期间劝退了好多队伍(当然也还有我们队)。有两个玩家在玩一种游戏,这种游戏里每个玩家有四种仆人(每种仆人都是那种特扛揍的那种)。
1、有护盾加亡语
2、只有护盾
3、只有亡语
4、啥也没有
然后护盾可以免疫一切伤害,亡语在这个仆人死后会召唤出一种攻击力等于白给(1)的藤曼。只要有极低的可能性能赢就能赢。
思路:既然只有有极低的可能性能赢就能赢的话,那就把我们这方当作决定聪明的玩家,对面就是一个憨憨玩家。我们发现,我们要尽量让我们的藤曼去撞对方的护盾,而让对方的藤曼来攻击我们的仆人。但是为了让藤曼尽可能多,我们这方先用只有亡语的,让后在用护盾加亡语的,然后再用只有护盾的,最后硬刚啥也没有的。而对于对手,我们先也是放掉只有亡语的,然后在用掉啥也没有的,而把有护盾加亡语的和只有护盾的放到后两位。这样,我们积累了足够多的藤曼之后就可以破了对方的护盾了。也就是我们尽可能地多存放藤曼,让对方的啥也没有的仆人尽可能地攻击我们的护盾。我们把双方的准备阶段都防在prepare函数里面。
代码:
#include<iostream> using namespace std; int a[6],b[6]; void prepare(){ if(a[3]) a[5]++,a[3]--; //按亡语,护盾+亡语,护盾,啥也没有的顺序 else if(a[1]) a[1]--,a[3]++; else if(a[2]) a[2]--,a[4]++; else a[4]--; if(b[3]) b[3]--,b[5]++; //按亡语,啥也没有,护盾+亡语,护盾的顺序 else if(b[4]) b[4]--; else if(b[1]) b[3]++,b[1]--; else b[2]--,b[4]++; } int main(){ int t; cin>>t; while(t--){ a[5]=b[5]=0; for(int i=1;i<=4;i++) cin>>a[i]; for(int i=1;i<=4;i++) cin>>b[i]; while(a[1]+a[2]+a[3]+a[4]&&b[1]+b[2]+b[3]+b[4]){ prepare(); //双方先进行准备 if(a[3]+a[4]) b[5]=0; //只要我方有仆人,对面的藤曼就等于白给 if(a[5]&&b[1]+b[2]){ //只要我们有藤曼,就拿去撞对方的护盾 if(b[1]) b[1]--,b[3]++; else b[2]--,b[4]++; a[5]=0; } } if(b[1]+b[2]+b[3]+b[4]||!(a[1]+a[2]+a[3]+a[4])&&a[5]<=b[5]) cout<<"No"<<endl; else cout<<"Yes"<<endl; } return 0; }
I、Tournament
题意:有n个队伍,每个队伍都要与其他队伍之间进行一个比赛,问怎么样的安排才能使得每个队伍停留的时间尽可能地少。
思路:构造+贪心。我们将队伍直接分为两部分,前半部分和后半部分。前半部分先进行比赛,然后前半部分与后半部分之间进行比赛,最后是后半部分内部之间进行比赛。
代码:
#include<iostream> using namespace std; int main(){ int t; cin>>t; while(t--){ int n; cin>>n; for(int i=2;i<=n/2;i++){ //前n/2个人之间互相进行比赛 for(int j=1;j<i;j++){ cout<<j<<" "<<i<<endl; } } for(int i=n/2+1;i<n;i++){ //后半部分与前半部分之间相互比赛 for(int j=1;j<=n-i;j++){ cout<<i<<" "<<j<<endl; } } for(int i=1;i<=n/2;i++){ //前半部分与后半部分之间相互比赛 for(int j=n-i+1;j<=n;j++){ cout<<j<<" "<<i<<endl; } } for(int i=n/2+1;i<n;i++){ for(int j=i+1;j<=n;j++){ cout<<j<<" "<<i<<endl; } } } return 0; }
E、Game
题意:给出一个类似于俄罗斯方块那样高度的序列,问从右往左进行推滑块的操作(滑块会受重力作用掉落),问最后在所有滑块中高度最高最小化是多少。
思路:我们可以知道如果某个区间内后面的高度小于前面的高度的话,我们就没有必要进行操作,而如果是一个单调递增的区间的话,我们就可以将这个区间平均化,如果某个区间后面又是一个单调减的区间的话,那么其实对我们的ans没有影响,但是到了一定的程度上又对我们的区间会产生影响,因此问题就转化为求每个位置前缀和的平均,取最大前缀和平均即可。
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<vector> using namespace std; typedef long long ll; ll a[100010],pre[100010]; int main(){ int T; scanf("%d",&T); while(T--){ vector<ll> v; int n; scanf("%d",&n); pre[0]=0; ll ans=-1; for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); pre[i]=pre[i-1]+a[i]; ll tmp=pre[i]/i; if(pre[i]%i!=0) tmp++; ans=max(ans,tmp); } printf("%lld\n",ans); } return 0; }