The 2023 ICPC Asia Hangzhou Regional Contest (The 2nd Universal Cup. Stage 22: Hangzhou)
M.V-Diagram
题意:
V图:长度>=3,且包含一个最小值,最小值前面的数降序排列,最小值后面的数升序排列。
给定一个V图a,找出在V图a中平均值最大的V图b。
思路:
找到V图中的最小值标记下标为b,此时从b点动态规划会发现:
从b点开始,左边的数均比b大,加上后平均值一定比当前的数大,但是此时如果向右边规划,不能保证加上右边的数平均数一定会增大,因为无法保证右边的数比当前的平均数大。
因此可以将V图的平均数大的区域分为三部分:
1 1~b+1
2 b-1~n
3 1~n
无法保证哪边平均值,因此取得三个范围的平均数进行比较取最大即可
Solved
const int N=3e5+10;
int a[N];
void solve()
{
int n;cin>>n;
double sum=0,sum1=0,sum2=0;
int mi=INT_MAX,b;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];//存所有范围值
if(a[i]<mi){
mi=a[i];
b=i;//记录最小值下标
}
}
for(int i=1;i<=b+1;i++){//存左段范围值,保证是V图
sum1+=a[i];
}
for(int i=b-1;i<=n;i++){//存右段范围值,保证是V图
sum2+=a[i];
}
//加上一段绝对值比较优,加上另一段不清楚,因此三个范围全计算出进行比较
double x=sum/n;//两段均加
double y=sum1/(b+1);//加左段不加右段
double z=sum2/(n-(b-1)+1);//加右段不加左段
double ans=max(x,max(y,z));
printf("%.20lf\n",ans);
}
D. Operator Precedence
题意:
给定n,构造出长度2n的序列满足:
1 a1* a2+a3* a4+a5* a6+…+a2n-1* a2n
2 a1* (a2+a3)* (a2+a4)* (a5+a6) …*a2n
保证1,2式子值相同
思路:
通过分析成分,2中 中间两数先加后全乘的递增程度要比1中 两两想乘在想加的递增程度大的
因此可以令2中的( ai +( ai+1) ) 为1,再构造a1,a2n,所以令ai=-1,ai+1=2;
此时
1 a1* (-1)+(-2)+(-2)+…+2* a2n
2 a1* a2n
令a1=1,解出a2n=2n-3
Solved
void solve()
{
int n;cin>>n;
cout<<"1 ";
int q=n-1;
while(q--){
cout<<"-1 2 ";
}
cout<<2*n-3<<endl;
}
J.Mysterious Tree
题意:
交互题 每次询问答案由输出给出。换行符用endl可不清空缓冲区,若用’\n’应使用cout.flush();清除缓冲区
给出n个节点,确定n个节点的连接方式
菊:当且仅当存在一个节点u,使得其他所有节点v都与u有节点。
链:当且仅当存在一个排序使得i 有pi->pi+1, p1,p2…pn称为链。
思路:
链中每个节点最多有两条边,而菊 中心节点大于等于三条边相连,因此只需找到任意一条连接的边,再找出两个不同于此边上的节点,判断此边上的节点(若是菊,则有一个一定是中心节点)是否可以与这两个不同的点连接,如果中心节点可以和这两个节点相连,则是菊,否则是链。
Solved
参考学长代码
const int N=1e5+10;
int a[N];
int n;
int ask(int u,int v)
{
cout<<"? "<<u<<" "<<v<<endl;//询问问题
int x;cin>>x;
return x;//给出答案
}
int check(int u,int v)
{
int k=0;
for(int i=1;i<=n;i++){
if(i!=u&&i!=v)//确定两个不同于u,v的点
a[k++]=i;//存入数组中使用
if(k==2) break;
}
int sum=0;
if(ask(u,a[0])==1){//如果u与a[0]相连,则判断u是否与a[1]相连,相连则菊,不想连则链
sum=1+ask(u,a[1]);
}else{//如果u与a[0]不相连,则判断v是否与a[1],a[2]相连
sum=ask(v,a[0])+ask(v,a[1]);
}
if(sum==2) return 2;
else return 1;//如果sum值为0,是链,在链中v可既不与a[0]又不与a[1]连
}
void solve()
{
cin>>n;
int res=-1;
for(int i=1;i<=n;i+=2){
if(ask(i,i%n+1)==1){//只需找到一条相连接的边即可
res=check(i,i%n+1);//再找两个不同的点判断
break;
}
}
if(res==-1) cout<<"! 1"<<endl;
else cout<<"! "<<res<<endl;
}
模板:
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
}
signed main()
{
std::ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n;cin>>n;
while(n--){
solve();
}
return 0;
}