文章目录
- [M. V-Diagram](https://codeforces.com/gym/104976/problem/M)
- [J. Mysterious Tree](https://codeforces.com/gym/104976/problem/J)
- [D.Operator Precedence](https://codeforces.com/gym/104976/problem/D)
- [G. Snake Move](https://codeforces.com/gym/104976/problem/G)
- [H. Sugar Sweet II](https://codeforces.com/gym/104976/problem/H)
M. V-Diagram
题意:
给一个V图,求一个连续子序列平均值最大的V图
首先,要保证是V字形,最小的和左右两个是一定要保留的,然后,如果某个小的选了,那么选比它大的肯定是提高平均值的,所以把V字形的一边全选了,至于为什么不把另一边也一起选了,是因为,有可能已经选的一边数非常大,而另一边数非常小,那么会拉低平均值,同理,只选另一边,以及选择整个V字形
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=3e5+10;
int a[N];
int n;
void solve() {
cin>>n;
int minn=2e9;
for(int i=1;i<=n;i++) cin>>a[i],minn=min(minn,a[i]);
double ans=0;
int idx;
for(int i=1;i<=n;i++){
if(a[i]==minn){
idx=i;
break;
}
}
double sum=0;
for(int i=1;i<=idx+1;i++) sum+=a[i];
ans=max(ans,sum/(idx+1));
sum=0;
for(int i=n;i>=idx-1;i--) sum+=a[i];
ans=max(ans,sum/(n-idx+2));
sum=0;
for(int i=1;i<=n;i++) sum+=a[i];
ans=max(ans,sum/n);
printf("%.10f\n",ans);
}
signed main() {
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
int t=1;
cin>>t;
while(t--) {
solve();
}
return 0;
}
J. Mysterious Tree
题意:
一棵树,可能是链或者菊花,每次询问一条边存在性,确定是链还是菊 花。询问次数⌈n 2⌉+3
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {
cin>>n;
if(n%2==0){
for(int i=1;i<=n;i+=2){
cout<<"? "<<i<<' '<<i+1<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
if(i==1){
cout<<"? "<<1<<' '<<3<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
cout<<"? "<<1<<' '<<4<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
cout<<"! "<<2<<endl;
cout.flush();
return;
}
else{
cout<<"! "<<1<<endl;
cout.flush();
return;
}
}
else{
cout<<"? "<<2<<' '<<3<<endl;
cout.flush();
int x;
cin>>x;
if(x==0){
cout<<"! "<<1<<endl;
cout.flush();
return;
}
else{
cout<<"? "<<2<<' '<<4<<endl;
cout.flush();
int x;
cin>>x;
if(x==0){
cout<<"! "<<1<<endl;
cout.flush();
return;
}
else{
cout<<"! "<<2<<endl;
cout.flush();
return;
}
}
}
}
else{
cout<<"? "<<i<<' '<<1<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
cout<<"? "<<i<<' '<<2<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
cout<<"! "<<2<<endl;
cout.flush();
return;
}
else{
cout<<"! "<<1<<endl;
cout.flush();
return;
}
}
else{
cout<<"? "<<i+1<<' '<<1<<endl;
cout.flush();
int x;
cin>>x;
if(x==0){
cout<<"! "<<1<<endl;
cout.flush();
return;
}
else{
cout<<"? "<<i+1<<' '<<2<<endl;
cout.flush();
int x;
cin>>x;
if(x==0){
cout<<"! "<<1<<endl;
cout.flush();
return;
}
else{
cout<<"! "<<2<<endl;
cout.flush();
return;
}
}
}
}
}
}
cout<<"! "<<1<<endl;
cout.flush();
}
else{
for(int i=1;i<=n-1;i+=2){
cout<<"? "<<i<<' '<<i+1<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
if(i==1){
cout<<"? "<<1<<' '<<3<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
cout<<"? "<<1<<' '<<4<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
cout<<"! "<<2<<endl;
cout.flush();
return;
}
else{
cout<<"! "<<1<<endl;
cout.flush();
return;
}
}
else{
cout<<"? "<<2<<' '<<3<<endl;
cout.flush();
int x;
cin>>x;
if(x==0){
cout<<"! "<<1<<endl;
cout.flush();
return;
}
else{
cout<<"? "<<2<<' '<<4<<endl;
cout.flush();
int x;
cin>>x;
if(x==0){
cout<<"! "<<1<<endl;
cout.flush();
return;
}
else{
cout<<"! "<<2<<endl;
cout.flush();
return;
}
}
}
}
else{
cout<<"? "<<i<<' '<<1<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
cout<<"? "<<i<<' '<<2<<endl;
cout.flush();
int x;
cin>>x;
if(x==1){
cout<<"! "<<2<<endl;
cout.flush();
return;
}
else{
cout<<"! "<<1<<endl;
cout.flush();
return;
}
}
else{
cout<<"? "<<i+1<<' '<<1<<endl;
cout.flush();
int x;
cin>>x;
if(x==0){
cout<<"! "<<1<<endl;
cout.flush();
return;
}
else{
cout<<"? "<<i+1<<' '<<2<<endl;
cout.flush();
int x;
cin>>x;
if(x==0){
cout<<"! "<<1<<endl;
cout.flush();
return;
}
else{
cout<<"! "<<2<<endl;
cout.flush();
return;
}
}
}
}
}
}
cout<<"? "<<n<<' '<<1<<endl;
cout.flush();
int x;
cin>>x;
cout<<"? "<<n<<' '<<2<<endl;
cout.flush();
int y;
cin>>y;
cout<<"? "<<n<<' '<<3<<endl;
cout.flush();
int z;
cin>>z;
if(x==1&&y==1&&z==1){
cout<<"! "<<2<<endl;
cout.flush();
}
else {
cout<<"! "<<1<<endl;
cout.flush();
}
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--) {
solve();
}
return 0;
}
D.Operator Precedence
题意:
构造2*n个数,满足
( a 1 a_1 a1 a 2 a_2 a2)+( a 3 a_3 a3 a 4 a_4 a4)+…( a 2 n − 1 a_{2n-1} a2n−1 a 2 n a_{2n} a2n)= a 1 a_1 a1( a 2 a_2 a2+ a 3 a_3 a3)( a 4 a_4 a4+ a 5 a_5 a5)…( a 2 n − 2 a_{2n-2} a2n−2+ a 2 n − 1 a_{2n-1} a2n−1) a 2 n a_{2n} a2n
且最终结果不等于0
构造题,往往用最特殊,最简单的,自己构造,肯定简单化而不是复杂化
由于中间全部乘起来,如果存在大于2的数,那么最后会非常非常大,不可控,所以构造若干个1相乘
设序列为x -1 2 -1 2…-1 2 y
所以x * y = -x-(n-2) * 2+2 * y
令y=1,则x=-x-2 * n + 4 +2
得2 * x= 6 - 2 * n
得 x =3 - n
由于所有数都不能为0,所以特判一下n为3的情况,直接抄样例
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
int n;
void solve() {
cin>>n;
if(n==3){
cout<<"1 -10 6 6 -10 1"<<endl;
return;
}
cout<<3-n<<' ';
for(int i=0;i<(2*n-2)/2;i++){
cout<<-1<<' '<<2<<' ';
}
cout<<1<<endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--) {
solve();
}
return 0;
}
G. Snake Move
题意:
给定n×m地图上的一条长度为k的贪吃蛇。每次操作可以控制贪吃蛇 移动一步或者缩短一格蛇身。对于每个位置,求从初始状态出发最少需要多少次操作使得蛇头到达该处,平方和模 2 64 2^{64} 264
首先分析一下操作,要么蛇头移动一格,身子往前补充原来的位置,蛇尾的位置就空出来了,要么蛇头不动,直接把蛇尾的位置空出来
假设只有蛇头,那么蛇头到任何位置只要跑一个最简单的最短路就可以了,但是由于每次移动只有蛇尾能空出来,所以对于不是蛇身的位置直接跑最短路,而蛇身的位置不能只是简单的最短路,蛇的第i截是在第k-i次之后才空出来,所以我们需要要取max(k-i+1,dist+1)
注意,模 2 64 2^{64} 264就是unsigned int long long
#include<bits/stdc++.h>
#define endl '\n'
//#define int long long
using namespace std;
typedef pair<int,int>PII;
typedef pair<int,PII>PIII;
const int N=3010;
int n,m,k;
int cnt[N][N];
long long dist[N][N];
char s[N][N];
bool vis[N][N];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
void dijkstra(int a,int b){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
dist[i][j]=1e18;
}
}
dist[a][b]=0;
priority_queue<PIII,vector<PIII>,greater<PIII>>heap;
heap.push({0,{a,b}});
while(heap.size()){
auto t=heap.top();
heap.pop();
int d=t.first,x=t.second.first,y=t.second.second;
if(vis[x][y]) continue;
vis[x][y]=true;
for(int i=0;i<4;i++){
int tx=x+dx[i],ty=y+dy[i];
if(tx<1||tx>n||ty<1||ty>m) continue;
if(vis[tx][ty]||s[tx][ty]=='#') continue;
if(dist[tx][ty]>max(d+1,cnt[tx][ty]+1)){
dist[tx][ty]=max(d+1,cnt[tx][ty]+1);
heap.push({dist[tx][ty],{tx,ty}});
}
}
}
}
void solve() {
cin>>n>>m>>k;
int sta,stb;
for(int i=1;i<=k;i++){
int x,y;
cin>>x>>y;
cnt[x][y]=k-i;
if(i==1) sta=x,stb=y;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>s[i][j];
}
}
dijkstra(sta,stb);
unsigned int long long ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(dist[i][j]==1e18) continue;
ans+=dist[i][j]*dist[i][j];
}
}
cout<<ans<<endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--) {
solve();
}
return 0;
}
H. Sugar Sweet II
题意:
n 个数a1,a2…an,有 n 个事件,每个事件形如:如果 ai<bi,则 ai = ai +wi,事件随机顺序发生,问每个数的期望
首先,事件是随机发生的,那么肯定和事件发生的顺序有关,我们来分析一下
如果a[i]<a[b[i]],那么事件一定会发生,因为a[b[i]]只能增不能减,所以不管事件的顺序是怎么样的,a[i]始终小于a[b[i]],所以a[i]必定能加上w[i],也就是说a[i]的期望就是a[i]+w[i]
如果a[i]>=a[b[i]]+w[b[i]],那么事件一定不会发生,因为就算先发生a[b[i]]+w[b[i]]这一事件,a[i]也不可能小于a[b[i]],所以a[i]的期望就是a[i]
如果a[b[i]]<=a[i]<a[b[i]]+w[b[i]],那么a[i]+w[i]这一事件发生当且仅当a[b[i]]+w[b[i]]这一事件发生,具有严格的依赖关系
trick:
如果出现严格的依赖关系,可以建图
如果a[i]+w[i]这一事件发生当且仅当a[b[i]]+w[b[i]]这一事件发生,那么连一条边,b[i]->i,建好图之后,当前事件发生当且仅当它前面的事件全部发生并且顺序必须是按照建图的顺序来的,假设它前面有x-1个事件,那么随便排列,只有一种是可以的,概率就是1/x!
所以我们预处理一下深度就可以了
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=5e5+10,mod=1e9+7;
int a[N],b[N],w[N];
int fac[N],ifac[N];
int dist[N];
int n;
int qmi(int a,int b){
int res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
vector<vector<int>>e(N);
void dfs(int u){
for(auto v:e[u]){
dist[v]=dist[u]+1;
dfs(v);
}
}
void solve() {
cin>>n;
for(int i=1;i<=n;i++) e[i].clear(),dist[i]=0;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++) cin>>w[i];
for(int i=1;i<=n;i++){
if(a[i]<a[b[i]]) dist[i]=1;
else if(a[i]>=a[b[i]]+w[b[i]]) dist[i]=0;
else e[b[i]].push_back(i);
}
for(int i=1;i<=n;i++){
if(dist[i]==1){
dfs(i);
}
}
for(int i=1;i<=n;i++){
if(dist[i]==0) cout<<a[i]<<' ';
else if(dist[i]==1) cout<<(a[i]+w[i])%mod<<' ';
else cout<<((a[i]+w[i]*ifac[dist[i]])%mod+mod)%mod<<' ';
}
cout<<endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
//预处理阶乘以及阶乘的逆元
fac[0]=ifac[0]=1;//0的阶乘是1,0的阶乘的逆元也是1
for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%mod;//预处理阶乘
ifac[N-1]=qmi(fac[N-1],mod-2);//先求出fac[N-1]的逆元,由于(n+1)!=n!*(n+1)==>n!^(-1)=(n+1)!^(-1)*(n+1),所以也可以通过递推得到阶乘的逆元
for(int i=N-2;i>=1;i--) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
cin>>t;
while(t--) {
solve();
}
return 0;
}