test6 3-21 2021省选模拟赛six
文章目錄
- 考試復盤
- rng
- lg
- pm
考試復盤
第一題,乍一看期望,又不會做了,乍二看,暴力好像可以202020跑路,屁顛屁顛敲完死活過不了這個簡單的樣例;開始(⊙⊙?)乍三看,實數??完了直接哦豁,麻溜拍拍屁股走人
第二題我一看一坨數學公式,人直接傻掉@_@,這種直接問公式答案的少不了使勁推式子的過程,而且非常了解自己的數學水平,肯定不行;想法肯定會有就是拆gcdgcdgcd的質因子分開算貢獻;推了一會兒,發現確實不行,快速暴力下一個(╥╯^╰╥)
第三題有點感覺,自己手玩了幾組,找了下規律,感覺跟逆序對個數和區間長度關系掛鉤,而且好像都是最多只能減少111,因為相比起來做出第三題的概率更大,兩個小時多都在淦這一道,想到了可持久化線段樹,差分算區間逆序對個數,下標和值域是同樣區間,但是卡在了最后這么找這一段的時間上,只會暴力跳ヽ(○?)ノ?
誰曾想,xez的算法,左掃一遍,又掃一遍,最后變幾個能ACACAC,這種做法之高叼!
數學題——就是要敢猜,先猜后證ball哥教的
rng
考慮對于每個i<ji<ji<j,計算a[i]>a[j]a[i]>a[j]a[i]>a[j]的概率并求和
假設(li,ri)=(l1,r1),(lj,rj)=(l2,r2)(l_i,r_i)=(l_1,r_1),(l_j,r_j)=(l_2,r_2)(li?,ri?)=(l1?,r1?),(lj?,rj?)=(l2?,r2?)
先從l1=l2=0l_1=l_2=0l1?=l2?=0入手
若r1≤r2r_1\le r_2r1?≤r2?,則概率為r12r2=r122r1r2\frac{r_1}{2r_2}=\frac{r_1^2}{2r_1r_2}2r2?r1??=2r1?r2?r12??
這個實數的概率很像JJ晚上給我做的物理高必刷必修二里面的一道積分滑動摩擦力做功,長度和為nnn的mmm個小物塊從光滑面滑入粗糙面,利用積分求解的
若r1>r2r_1>r_2r1?>r2?,則概率為1?r22r1=2r1r2?r222r1r21-\frac{r_2}{2r_1}=\frac{2r_1r_2-r_2^2}{2r_1r_2}1?2r1?r2??=2r1?r2?2r1?r2??r22??
r22r1\frac{r_2}{2r_1}2r1?r2??就是假如j<ij<ij<i的逆序對概率,用111減去則為i<ji<ji<j時的逆序對概率
用三個樹狀數組維護1,x,x21,x,x^21,x,x2
接下來考慮(l1,r1),(l2,r2)(l_1,r_1),(l_2,r_2)(l1?,r1?),(l2?,r2?)
容斥答案為f(r1,r2)?f(l1,r2)?f(r1,l2)+f(l1,l2)2(r1?l1)(r2?l2)\frac{f(r_1,r_2)-f(l_1,r_2)-f(r_1,l_2)+f(l_1,l_2)}{2(r_1-l_1)(r_2-l_2)}2(r1??l1?)(r2??l2?)f(r1?,r2?)?f(l1?,r2?)?f(r1?,l2?)+f(l1?,l2?)?
非常常見的二維平面容斥方法
注意不應該直接減概率,fff相當于是合法面積
#include <cstdio> #include <algorithm> using namespace std; #define maxn 100005 #define int long long #define mod 998244353 pair < int, int > p[maxn][2]; int n, cnt; int l[maxn], r[maxn], x[maxn << 1], num[2];int qkpow( int x, int y ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }struct node {int val;int t[maxn << 1];int lowbit( int x ) {return x & ( -x );}void add( int x, int y ) {val = ( val + y ) % mod;for( int i = x;i <= cnt;i += lowbit( i ) )t[i] = ( t[i] + y ) % mod;}int query( int x ) {if( x == cnt ) return val;int ans = 0;for( int i = x;i;i -= lowbit( i ) )ans = ( ans + t[i] ) % mod;return ans;}int query( int l, int r ) {return ( query( r ) - query( l - 1 ) ) % mod;} }A, B, C;#define opt first #define val secondsigned main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) {scanf( "%lld %lld", &l[i], &r[i] );p[i][0] = make_pair( -1, l[i] );p[i][1] = make_pair( 1, r[i] );x[++ cnt] = l[i], x[++ cnt] = r[i];}sort( x + 1, x + cnt + 1 );int ans = 0;for( int i = 1;i <= n;i ++ ) {int inv = qkpow( r[i] - l[i], mod - 2 );pair < int, int > now;for( int j = 0;j <= 1;j ++ ) {now = p[i][j];num[j] = lower_bound( x + 1, x + cnt + 1, now.val ) - x;ans = ( ans + now.opt * C.query( 1, num[j] ) * inv % mod ) % mod;ans = ( ans + now.opt * ( B.query( num[j] + 1, cnt ) * 2 * now.val % mod- A.query( num[j] + 1, cnt ) * now.val % mod * now.val % mod) * inv % mod) % mod; }for( int j = 0;j <= 1;j ++ ) {now = p[i][j];A.add( num[j], now.opt * inv % mod );B.add( num[j], now.opt * now.val * inv % mod );C.add( num[j], now.opt * now.val * now.val % mod * inv % mod );}}ans = ans * qkpow( 2, mod - 2 ) % mod;printf( "%lld\n", ( ans + mod ) % mod );return 0; }lg
∏lcmgcd=∏lcm∑d∣xφ(d)\prod lcm^{gcd}=\prod lcm^{\sum_{d|x}φ(d)}∏lcmgcd=∏lcm∑d∣x?φ(d)
指數相加拆出來即為相乘
=∏d∏d∣x?ilcmφ(d)=∏d(∏x?i≤?md?(lcm?d))φ(d)=\prod_ozvdkddzhkzd\prod_{d|x*i}lcm^{φ(d)}=\prod_ozvdkddzhkzd\bigg(\prod_{x*i\le \lfloor\frac{m}ozvdkddzhkzd\rfloor}(lcm*d)\bigg)^{φ(d)}=d∏?d∣x?i∏?lcmφ(d)=d∏?(x?i≤?dm??∏?(lcm?d))φ(d)
把ddd拆出來
=∏d(∏x?i≤?md?lcm)φ(d)?dφ(d)?(?md?)n=\prod_ozvdkddzhkzd\bigg(\prod_{x*i\le \lfloor\frac{m}ozvdkddzhkzd\rfloor}lcm\bigg)^{φ(d)}*d^{φ(d)*(\lfloor\frac{m}ozvdkddzhkzd\rfloor)^n}=d∏?(x?i≤?dm??∏?lcm)φ(d)?dφ(d)?(?dm??)n
計算lcmlcmlcm,就單獨考慮每個質因子的貢獻,用容斥計算,類似于xxx的倍數的個數?-?是x2x^2x2的倍數的個數…
Damo的題解
pm
考慮一個長度最小為lenlenlen的段,一定操作了len?1len-1len?1次(否則該段一定可以分成兩個更小的段各自獨立操作
不然就直接lenlenlen次一一單獨變化即可
而且len?1len-1len?1次操作后,下標和值就應該一一對應了
問題轉換成,在原序列中找出若干不相交的段,每個段的長度等于這個段中的逆序對個數+1+1+1,并且每個段占用的下標和包含的元素集合相同,每個這樣的段都能省一次操作
考慮對于每個段右端點(如果有
找到最短的占用下標和包含元素集合相同的段
只有這樣的段是候選段
如果選取了更長的段,顯然可以用這個段將它分開
并且分開的兩段中也恰有一段滿足逆序對個數比長度少一
接下來需要對于每個段的右端點rrr,找到最短的段[l,r][l,r][l,r]滿足{al,al+1...ar}=[l,r]\{a_l,a_{l+1}...a_{r}\}=[l,r]{al?,al+1?...ar?}=[l,r]
max{al,...,ar}=rmax\{a_l,...,a_r\}=rmax{al?,...,ar?}=r可以用ststst表預處理
sumi=lrai?i=0sum_{i=l}^ra_i-i=0sumi=lr?ai??i=0掃一遍就可以做了,一段區間和為000,說明前lll和前rrr和一樣
nxd[l,r]=r?lnxd[l,r]=r-lnxd[l,r]=r?l轉化為差分
#include <map> #include <cmath> #include <cstdio> #include <iostream> using namespace std; #define int long long #define maxn 200005 map < int, int > last; int n, cnt; int a[maxn], id[maxn], nxd[maxn], L[maxn], ans[maxn]; int tree[maxn], f[maxn], g[maxn], pre[maxn]; int rt[maxn], t[maxn * 30], lson[maxn * 30], rson[maxn * 30]; int st[maxn][20];int lowbit( int x ) {return x & ( -x ); }void add( int x ) {x = n - x + 1;for( int i = x;i <= n;i += lowbit( i ) )tree[i] ++; }int query( int x ) {x = n - x + 1;int tot = 0;for( int i = x;i;i -= lowbit( i ) )tot += tree[i];return tot; }void insert( int pre, int &now, int l, int r, int pos ) {if( ! now ) now = ++ cnt;t[now] = t[pre] + 1;if( l == r ) return;int mid = ( l + r ) >> 1;if( pos <= mid ) rson[now] = rson[pre], insert( lson[pre], lson[now], l, mid, pos );else lson[now] = lson[pre], insert( rson[pre], rson[now], mid + 1, r, pos ); }int query( int now, int l, int r, int L, int R ) {if( L > R ) return 0;if( L <= l && r <= R ) return t[now];int mid = ( l + r ) >> 1;if( R <= mid ) return query( lson[now], l, mid, L, R );else if( mid < L ) return query( rson[now], mid + 1, r, L, R );else return query( lson[now], l, mid, L, R ) + query( rson[now], mid + 1, r, L, R ); }void init() {for( int i = 1;i <= n;i ++ ) st[i][0] = a[i];for( int j = 1;j < 20;j ++ )for( int i = 1;i <= n;i ++ )if( i + ( 1 << j - 1 ) > n ) break;else st[i][j] = max( st[i][j - 1], st[i + ( 1 << j - 1 )][j - 1] ); }int ask( int l, int r ) {int i = log( r - l + 1 ) / log( 2 );return max( st[l][i], st[r - ( 1 << i ) + 1][i] ); }signed main() {scanf( "%lld", &n );int sum = 0;last[0] = 1;for( int i = 1;i <= n;i ++ ) {scanf( "%lld", &a[i] );insert( rt[i - 1], rt[i], 1, n, a[i] );nxd[i] = nxd[i - 1] + query( a[i] + 1 );add( a[i] );sum += a[i] - i;L[i] = last[sum];//上一次sum的位置與現在sum的位置中間的和即為0last[sum] = i + 1;id[a[i]] = i;}init();for( int i = 1;i <= n;i ++ ) {if( L[i] ) {//如果成段int l = L[i], r = i;int tot = nxd[r] - nxd[l - 1] - query( rt[l - 1], 1, n, r + 1, n ) * ( r - l + 1 );//[1,l-1]對于[l,r]區間的逆序對數量就是[1,l-1]中大于r的個數*(r-l+1),[l,r]值出現的位置一定是在區間[l,r]if( tot == r - l && ask( l, r ) == r ) {f[i] = f[pre[l - 1]] + 1;//段數+1g[i] = pre[l - 1];//上一個段的結束位置}}pre[i] = pre[i - 1];//遞推傳遞上一個段的結束位置if( f[pre[i - 1]] < f[i] ) pre[i] = i;//新段的右端點}cnt = 0;int r = pre[n];while( r ) {int l = L[r];for( int i = r;i >= l;i -- )for( int j = id[i];j < i;j ++ ) {swap( id[a[j]], id[a[j + 1]] );swap( a[j], a[j + 1] );ans[++ cnt] = j;}r = g[r];}printf( "%d\n", cnt );for( int i = 1;i <= cnt;i ++ )printf( "%d ", ans[i] );return 0; }總結
以上是生活随笔為你收集整理的test6 3-21 2021省选模拟赛six的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Amarra4音乐播放器mac版本怎么使
- 下一篇: test 7 3-22 2021省选模拟