比赛链接:Dashboard - The 2023 ICPC Asia Hangzhou Regional Contest (The 2nd Universal Cup. Stage 22: Hangzhou) - Codeforces
D
题意:给定 $n$ ,构造长为 $2n$ 的数列 $a$ ,使得
$$
(a_1 × a_2)+(a_3 × a_4)+ . . . +(a_{2n−1} × a_{2n}) = a_1 ×(a_2 + a_3)×(a_4 + a_5)× . . . ×(a_{2n−2} + a_{2n−1})× a_{2n}\neq 0
$$
且 $1\leq |a_i|\leq10^{10}$ 。
分奇偶讨论,令 $a_1 $ 与 $a_{2n}$ 为1,然后其余的数交替为-1和2,使得乘法的每一项和为1,然后留下最中间的两个数,解方程得出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <bits/stdc++.h> using namespace std;int main () { ios_base::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); int t; cin>>t; while (t--) { int n; cin>>n; int a[n*2 +1 ]; if (n==2 ) { cout<<"1 -3 -3 1\n" ; continue ; } if (n==3 ) { cout<<"1 -10 6 6 -10 1\n" ; continue ; } if (n==4 ) { cout<<"1 -15 10 -1 -1 10 -15 1\n" ; continue ; } a[1 ]=1 ,a[n*2 ]=1 ; for (int i=1 ;i<n/2 ;i++) { a[i*2 ]=-1 ; a[i*2 +1 ]=2 ; a[2 *n-i*2 +1 ]=-1 ; a[2 *n-i*2 ]=2 ; } if (n%2 ==0 ) { a[n]=1 ; a[n+1 ]=2 *(n-3 )-1 ; } if (n%2 ==1 ) { a[n-1 ]=1 ; a[n+2 ]=1 ; if (n==5 )a[n]=3 ,a[n+1 ]=-2 ; else { a[n]=1 ; a[n+1 ]=-2 *(n-6 )-2 ; } } int ans1=0 ,ans2=1 ; for (int i=1 ;i<=n;i++)ans1+=a[i*2 ]*a[i*2 -1 ]; for (int i=1 ;i<n;i++)ans2*=a[i*2 ]+a[i*2 +1 ]; for (int i=1 ;i<=n*2 ;i++)cout<<a[i]<<" " ;cout<<endl; } return 0 ; }
G
题意:给出一条蛇身上每个点的位置,蛇在网格内移动,每次可以选择上下左右移动一步或者将尾巴缩短一节。蛇不能到边界之外、不能与障碍相碰、不能和自身相碰。设 $f(i,j)$ 表示蛇头从开始位置到 $(i,j)$ 经历的最小步数。求 $\sum\sum f(i,j)^2$ 。
一开始想用bfs扩展,但是发现可能会导致重复更新。于是考虑最短路算法。
将所有点与相邻点之间连边,若不为蛇身的位置,直接由蛇头dij得到答案;
若为蛇身,假设蛇长 $k$ ,此时为蛇身上的第 $i$ 节,考虑当前步数 $d$ 与 $k-i$ 的关系,若 $d\leq k-i$ ,那么说明此时会和蛇相碰,那么答案就为 $d+(k-i-d+1)=k-i+1$ ,否则答案就为 $d$ ,将其加入优先队列等待更新。
但是这样做复杂度为 $O(nmlog(nm))$ ,刚好超时,可以优化一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 #include <bits/stdc++.h> using namespace std;#define ull unsigned long long #define ll long long int n,m,k;char g[3001 ][3001 ];bool vis[3001 ][3001 ];ll d[3001 ][3001 ]; int body[3001 ][3001 ];int hx,hy;int dx[4 ]={0 ,0 ,1 ,-1 };int dy[4 ]={1 ,-1 ,0 ,0 };void dij () { d[hx][hy]=0 ; priority_queue<pair<int ,pair<int ,int > >, vector<pair<int ,pair<int ,int > > >,greater<pair<int ,pair<int ,int > > > >q1; queue<pair<ll,pair<int ,int > > >q2; q1.push ({0 ,{hx,hy}}); while (q1.size () || q2.size ()) { int ans,x,y; if (q1.size () && q2.size ()) { if (q1.top ().first<q2.front ().first) { ans=q1.top ().first; x=q1.top ().second.first; y=q1.top ().second.second; q1.pop (); } else { ans=q2.front ().first; x=q2.front ().second.first; y=q2.front ().second.second; q2.pop (); } } else if (q1.size ()) { ans=q1.top ().first; x=q1.top ().second.first; y=q1.top ().second.second; q1.pop (); } else { ans=q2.front ().first; x=q2.front ().second.first; y=q2.front ().second.second; q2.pop (); } if (vis[x][y])continue ; vis[x][y]=1 ; for (int i=0 ;i<4 ;i++) { int nx=x+dx[i]; int ny=y+dy[i]; if (nx<1 || nx>n || ny<1 || ny>m || g[nx][ny]=='#' )continue ; if (body[nx][ny]==0 ) { ll tmp=d[x][y]+1 ; if (tmp<d[nx][ny]) { d[nx][ny]=tmp; q2.push ({tmp,{nx,ny}}); } } else { ll tmp=max (d[x][y]+1 ,(ll)k-body[nx][ny]+1 ); if (tmp<d[nx][ny]) { d[nx][ny]=tmp; q1.push ({tmp,{nx,ny}}); } } } } } int main () { ios_base::sync_with_stdio (false ); cin.tie (0 ); cout.tie (0 ); cin>>n>>m>>k; for (int i=1 ;i<=k;i++) { int x,y; cin>>x>>y; body[x][y]=i; if (i==1 )hx=x,hy=y; } for (int i=1 ;i<=n;i++)cin>>g[i]+1 ; memset (d,0x3f ,sizeof (d)); dij (); ull sum=0 ; for (int i=1 ;i<=n;i++) { for (int j=1 ;j<=m;j++) { if (d[i][j]<0x3f3f3f3f && g[i][j]!='#' )sum+=(ull)d[i][j]*d[i][j]; } } cout<<sum; return 0 ; }
H
题意:有 $n$ 个人,每个人最初有 $a_i$ 颗糖,现在有 $n$ 个事件按随机顺序发生:第 $i$ 个事件表示若 $i$ 的糖比 $b_i$ 的糖少,那么 $i$ 获得 $w_i$ 颗糖。求最后每个人获得的糖的期望。
只有当 $a[b_i]\leq a[i]<a[b_i]+w[b_i]$ 时 $i$ 才会得到奖励,否则 $i$ 的值是固定的。那么可以遍历所有有效限制关系,使具有如上关系的 $b_i$ 成为 $i$ 的父亲,然后若遇到确定的 $i$ ,那么打上标记,使其成为根节点。这棵树代表了先后顺序,只有父节点获得了糖,子节点才会获得糖。
最后会构成很多棵树,从根节点往下遍历:若根节点的值是确定的且不会获得糖,那么这棵子树的所有子节点都不会获得糖;若根节点能获得糖,那么往下遍历,假设从根到某个点经历了 $x$ 个点,那么该点获得糖的概率就是 $\frac{1}{x!}$ 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include <bits/stdc++.h> #define int long long using namespace std;const int N=5e5 +10 ,mod=1e9 +7 ;int n;int a[N],b[N],w[N];int inv[N],jcinv[N];int cnt,head[N],nxt[N],to[N];bool h[N],rt[N],vis[N];int ans[N];inline void add (int u,int v) { nxt[++cnt]=head[u]; head[u]=cnt; to[cnt]=v; } void dfs (int u,int tot) { ans[u]=(ans[u]+jcinv[tot]*w[u]%mod)%mod; for (int i=head[u];i;i=nxt[i]){ dfs (to[i],tot+1 ); } } signed main () { int T; scanf ("%lld" ,&T); inv[1 ]=1 ; jcinv[1 ]=1 ; for (int i=2 ;i<=5e5 ;++i){ inv[i]=(mod-mod/i)*inv[mod%i]%mod; jcinv[i]=jcinv[i-1 ]*inv[i]%mod; } while (T--){ scanf ("%lld" ,&n); cnt=0 ; for (int i=1 ;i<=n;++i) head[i]=0 ; for (int i=1 ;i<=n;++i) scanf ("%lld" ,&a[i]); for (int i=1 ;i<=n;++i) scanf ("%lld" ,&b[i]); for (int i=1 ;i<=n;++i) scanf ("%lld" ,&w[i]); for (int i=1 ;i<=n;++i){ ans[i]=a[i]; if (a[b[i]]<=a[i]&&a[i]<a[b[i]]+w[b[i]]) add (b[i],i),rt[i]=0 ; else rt[i]=1 ; } for (int i=1 ;i<=n;++i){ if (!rt[i]) continue ; if (a[i]>=a[b[i]]+w[b[i]]) continue ; dfs (i,1 ); } for (int i=1 ;i<=n;++i) printf ("%lld " ,ans[i]); puts ("" ); } }
J
题意:给出有 $n$ 个节点的树,这棵树有两种形态,要么是一条链,要么是有一个根节点,其有 $n-1$ 个儿子。现在可以询问 $\lceil\frac{n}{2}\rceil+3$ 次,每次询问可以问两个点,judge会告诉这两个点是否有边直接相连。确定这棵树是什么形态。
首先两两询问直到找到两个点 $u,v$ 有边相连,花费 $\lceil\frac{n}{2}\rceil$ 次。
对于 $u$ ,任找一个点 $x$ 询问,若 $u,x$ 有边,那么再随机询问 $u,y$ ,若有边则是状态2,若无边则一定是状态1。若 $u,x$ 无边,那么依次询问 $v,y$ 与 $v,z$ 得到答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 # include <bits/stdc++.h> using namespace std;int n;int main () { int m; scanf ("%d" ,&m); while (m --) { cin >> n; int i; for (i = 1 ; i <= n; i += 2 ) { int t; if (i != n) { cout << "? " << i << " " << i + 1 << '\n' ; cin >> t; } else { cout << "? " << i << " " << i - 1 << '\n' ; cin >> t; } if (!t) continue ; else { int j,k; if (i == 1 ) j = n, k = n - 1 ; else if (i == n - 1 ) j = 1 , k = 2 ; else if (i == n) j = 1 , k = 2 , --i; else j = i - 1 , k = i + 2 ; cout << "? " << i << " " << j << '\n' ; cin >> t; if (t) { cout << "? " << i << " " << k << '\n' ; cin >> t; if (t) { cout << "! 2\n" ; break ; } else { cout << "! 1\n" ; break ; } } else { cout << "? " << i + 1 << " " << j << '\n' ; cin >> t; if (t) { cout << "? " << i + 1 << " " << k << '\n' ; cin >> t; if (t) { cout << "! 2\n" ; break ; } else { cout << "! 1\n" ; break ; } } else { cout << "! 1\n" ; break ; } } } } if (i > n) cout << "! 1\n" ; } return 0 ; }
M
题意:给出一组长度为 $n,n\geq3$ 的数,使其在数字大小上形成 $V$ 型,求一个 $V$ 型连续子序列,使得其平均值最大。
$V$ 的一边全选,另一边一个一个枚举。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <bits/stdc++.h> using namespace std; #define LL long long int n;LL a[300010 ],mn,pm; double sum,avr;double ans;signed main () { int T; scanf ("%d" ,&T); while (T--){ ans=sum=0 ; mn=1e9 +10 ; scanf ("%d" ,&n); for (int i=1 ;i<=n;++i){ scanf ("%lld" ,a+i); if (a[i]<mn) mn=a[i],pm=i; } for (int i=1 ;i<=pm+1 ;++i) sum+=a[i]; ans=avr=sum/(pm+1 ); for (int i=pm+2 ;i<=n;++i){ sum+=a[i]; avr=sum/i; ans=max (ans,avr); } sum=0 ; for (int i=n;i>=pm-1 ;--i){ sum+=a[i]; } avr=sum/(n-pm+2 ); ans=max (ans,avr); for (int i=pm-2 ;i;--i){ sum+=a[i]; avr=sum/(n-i+1 ); ans=max (ans,avr); } printf ("%.15lf\n" ,ans); } return 0 ; }