首页 > 其他分享 >Noip模拟赛34

Noip模拟赛34

时间:2022-09-24 11:35:25浏览次数:55  
标签:ch return Noip int ll 元素 34 序列 模拟


noip模拟赛34
$$ 给定 1 \ldots N的一个排列 a ,M 次操作,操作有两种:1 l m r表示将al,al+1,...,ar改为merge(\{a_l,a_{l+1},...,a_m\},\{a_{m+1},a_{m+2},...,a_r\ 2 i ,表示询问 a_i的值是多少。其中 \operatorname{merge}(a, b)表示归并操作,其伪代码如下:[] $$ ~~~ def merge(a, b):   c=[]   while a.size() and b.size():     if a[0]<b[0]:       c. append(a[0])       a.pop_ front()     else:       c. append(b[0])       b.pop_ front()   return c+a+b ~~~
考虑一个平衡树做法,我们把变化的1区间split出来然后旋转一下维护平衡树的性质然后insert回去
QWQ: $$ 维护一个长度为 nn 的数列 a_i,共有 mm 个操作,这些操作共有两种。 ] \\
1 l r k 将区间 [l,r] 内的元素全部修改为 k \\
2 {l r c} 查询区间内是否存在出现次数大于 c 的数,如果存在,输出 laffey,否则输出 ayanami。
$$
区间推平很明显,是ODT(Old Driver Tree) 具体操作大概就是用set维护好多的桶 经典 set<node > : : iterator ~~~ #include<bits/stdc++.h> using namespace std; namespace fast_IO {     #define FASTIO     #define IOSIZE 100000     char ibuf[IOSIZE], obuf[IOSIZE];     char *p1 = ibuf, *p2 = ibuf, *p3 = obuf;     #ifdef ONLINE_JUDGE         #define getchar() ((p1==p2)and(p2=(p1=ibuf)+fread(ibuf,1,IOSIZE,stdin),p1==p2)?(EOF):(*p1++))         #define putchar(x) ((p3==obuf+IOSIZE)&&(fwrite(obuf,p3-obuf,1,stdout),p3=obuf),*p3++=x)     #endif//fread in OJ, stdio in local         #define isdigit(ch) (ch>47&&ch<58)     #define isspace(ch) (ch<33)     template<typename T> inline T read()     {         T s = 0; int w = 1; char ch;         while(ch=getchar(),!isdigit(ch)and(ch!=EOF)) if(ch=='-') w=-1;         if(ch == EOF) return false;         while(isdigit(ch)) s=s*10+ch-48,ch=getchar();         return s*w;     }     template<typename T> inline bool read(T &s)     {         s = 0; int w = 1; char ch;         while(ch=getchar(),!isdigit(ch)and(ch!=EOF)) if(ch=='-') w=-1;         if(ch == EOF) return false;         while(isdigit(ch)) s=s*10+ch-48,ch=getchar();         return s*=w, true;     }     inline bool read(char &s)     {         while(s = getchar(), isspace(s));         return true;     }     inline bool read(char *s)     {         char ch;         while(ch=getchar(),isspace(ch));         if(ch == EOF) return false;         while(!isspace(ch)) *s++ = ch, ch = getchar();         *s = '\000'; return true;     }     template<typename T> inline void print(T x)     {         if(x < 0) putchar('-'), x = -x;         if(x > 9) print(x/10);         putchar(x%10+48);     }     inline void print(char x){ putchar(x); }     inline void print(char *x){ while(*x) putchar(*x++); }     inline void print(const char *x)     { for(int i = 0; x[i]; i++) putchar(x[i]); }     #ifdef _GLIBCXX_STRING         inline bool read(std::string& s)         {             s = ""; char ch;             while(ch=getchar(),isspace(ch));             if(ch == EOF) return false;             while(!isspace(ch)) s += ch, ch = getchar();             return true;         }         inline void print(std::string x)         {             for(int i = 0, n = x.size(); i < n; i++)                 putchar(x[i]);         }     #endif//string     template<typename T, typename... T1> inline int read(T& a, T1&... other){ return read(a)+read(other...); }     template<typename T, typename... T1> inline void print(T a, T1... other){ print(a); print(other...); }
    struct Fast_IO{         ~Fast_IO(){ fwrite(obuf, p3-obuf, 1, stdout); }     }io;     template<typename T> Fast_IO& operator >> (Fast_IO &io, T &b){ return read(b), io; }     template<typename T> Fast_IO& operator << (Fast_IO &io, T b){ return print(b), io; }     #define cout io     #define cin io     #define endl '\n' } using namespace fast_IO; #define ll long long const int MAXN = 1e6 ; ll a[MAXN] ; struct node{     int l ;     int r ;     mutable int v ;
    node(ll l , ll r = 0 , ll v = 0) : l(l) , r(r) , v(v) {}     bool operator < (const node &a) const{         return l < a.l ;     }     }; set<node> s ;   set<node>::iterator split(int pos) {     set<node>::iterator it = s.lower_bound(node(pos)) ;     if(it != s.end() && it -> l == pos) return it ;     it -- ;     if(it -> r < pos) return s.end() ;     ll l = it -> l ;     ll r = it -> r ;     ll v = it -> v ;     s.erase(it) ;     s.insert(node(l,pos-1,v)) ;     return s.insert(node(pos,r,v)).first ; }
inline void assign(ll l , ll r ,ll x) {     set<node>::iterator itr = split(r + 1) , itl = split(l) ;     s.erase(itl,itr) ;     s.insert(node(l,r,x)) ; }
int G[MAXN]; inline bool calc(ll l , ll r , ll x) {     set<node>::iterator itr = split(r+1) , itl = split(l) ;     bool flag = 1 ;     for(set<node>::iterator it = itl ; it != itr ; it ++ )     {         int g = it->v ;         G[g] += (it -> r - it -> l + 1) ;         if(G[g] > x) flag = 0 ;     }     for(set<node>::iterator it = itl ; it != itr ; it ++ )     {         int g = it->v ;         G[g] -= (it -> r - it -> l + 1) ;     }     return flag ; } /* 6 1 1 4 5 1 4
4 2 1 5 2 2 1 6 3 1 5 6 1 2 1 6 3 lal */ ll m , n ;
int main() {     cin >> n ;     for(int i = 1 ; i <= n ; i ++ )     {         cin >> a[i] ;         s.insert(node(i,i,a[i])) ;     }     cin >> m ;     for(int i = 1 ; i <= m ; i ++ )     {         int opt ; int l , r ; int x ;         cin >> opt ;         cin >> l >> r >> x;         if(opt == 1)         {             assign(l , r , x) ;         }         else         {             bool flag = calc(l , r , x) ;             if(flag == false) cout << "laffey" ;             else cout << "ayanami" ;             cout << endl ;         }     } } ~~~
Problem B: Cigar Box
$$ 你有一个序列 \{1,2,3,\cdots,n\},你可以对它进行以下操作 mm 次:
删除任意一个数,将它加到这个序列的开头或末尾。 最后你需要得到序列 \{a_i\},这里 a_i是个 1\sim n1∼n 的排列。求合法的方案数模 998244353
两种操作方案相同当且仅当每次操作都选择了相同的元素,移动到了相同的方向。 $$
首先我们不妨先假设我们已经得到了一个操作序列。
因此,我们可以定义对某一个元素的最后一次移动,我们称它为该元素的关键操作。
我们不妨假设我们已经对某两个元素完成了关键操作。
则在当前序列中不在这两个元素之间的元素不能够成为这两个元素之间的元素,换句话说这两个元素间的元素若在目标序列中也在这两个元素之间则他们必然已经完成了他们的关键操作,或者他们完全不用操作。
因此我们得到了结论一:完成关键操作的元素在目标序列中是连续的。
我们考虑那些完全不用操作的元素可能在哪些位置。
我们不妨考虑第一个完成向左的关键操作的元素,则在目标序列中在该元素左边的元素必然需要操作。
第一个完成向右的关键操作的元素同理。
则最后我们发现在第一个完成向左的关键操作的元素和第一个向右的之间的元素是不用操作的。则在目标序列中,这些元素相对位置和原序列中一样,即这些元素单调递增。
我们不妨枚举目标序列中间的一段元素单调递增的区间,由性质一可以得到区间左边这些元素发生关键操作顺序和右边发生关键操作顺序,因此我们可以采用 dp 处理。
定义 dpi,l,r 表示进行 i 个操作后,在目标序列所选定的区间左边的元素中还有 l 个没有发生关键操作,右边还有 r 个没有发生关键操作。
则有转移方程:
dpi+1,l,r+=dpi,l,r×2×(l+r)dpi+1,l−1,r+=dpi,l,rdpi+1,l,r−1+=dpi,l,r 答案是 dpm,0,0。
于是我们得到了 O(n3×m) 的优秀做法。
我们发现我们每次 dp 的转移类似,我们考虑一次性 dp 预处理出所以可能用到的值。
因此类似的,我们可以定义 dpi,l,r 在目标序列所选定的区间左边的元素中还有 l 个没有发生关键操作,右边还有 r 个没有发生关键操作的一种序列变成 , 在 i 次内变成目标序列的方案数。
这次我们考虑倒序还原。
我们考虑当前的情况是如何得到的,考虑正序时这一步不是任何一个元素的关键操作,则得到这样一个情况我们上一步有 (l+r)×2 个选择。
若正序时这一步是关键操作,则正序时这一步到当前只有唯一一种方式。
则有方程:
dpi+1,l,r=dpi,l,r×2×(l+r)dpi,l+1,r=dpi,l,rdpi,l,r+1=dpi,l,r 对于这个方程我们可以理解为上一个序列是已经确定的,当前这一序列是不确定的,但无论当前长什么样,推到目标序列步数都是一样的,所以不影响。
于是我们得到了 O(n2m+n2) 的优秀算法。
考虑继续优化,我们发现第二个转移方程和第三个相似,我们不妨将后两维其压缩得到 fi,l+r 。转移类似,我们考虑但是实际上, f 计算值是只考虑了发生关键操作与否的顺序,而没有考虑左右关键操作的顺序,因此需要额外计算,于是有 dpi,l,r=fi,l+r×C(l+r,l) 。
~~~   #include<bits/stdc++.h> using namespace std; #define ll long long const ll MAXN = 3e3+10 ; const ll mod = 998244353 ; ll n , m ; ll a[MAXN],f[MAXN][MAXN],C[MAXN][MAXN]; int main() {     cin >> n >> m ;     for(ll i = 1 ; i <= n ; i ++ ) cin >> a[i] ;     f[m][0] = 1 ;     for(ll i = m - 1 ; ~i ; i -- )     {         for(ll j = 0 ; j <= n ; j ++ )         {             f[i][j] = 2 * f[i+1][j] * j % mod ;             if(j) f[i][j] = (f[i][j] + f[i+1][j-1]) % mod ;         }     }     for(ll i = 0 ; i <= n ; i ++ )     {         C[i][0] = 1 ;         for(ll j = 1 ; j <= i ; j ++ )         {             C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod ;         }     }     ll ans = 0 ;     for(ll i = 0 ; i <= n ; i ++ )       {         ans = (ans + C[n][i] * f[0][n]) % mod ;     }     for(ll i = 1 ; i <= n ; i ++ )     {         ans = (ans + C[n-1][i-1] * f[0][n-1]) % mod ;         for(ll j = i + 1 ; j <= n ; j ++ )         {             if(a[j] < a[j-1]) break ;             ans = (ans + C[n-(j-i+1)][i-1] * f[0][n-(j-i+1)]) % mod ;         }     }     cout << ans ;     return 0 ; }


~~~
C。wine Thief $$ 给你一个长为 nn 的序列 (a_1,a_2,\cdots,a_n 一种“成功”的子序列 a_{p_1},a_{p_2},\cdots,a_{p_m} 满足下面两个条件: 这个子序列的长度为 K(输入给出)即 m=K 在原序列中没有连续 D(本题 D=2)个元素同时在子序列中,不存在 p_i+1=p_{i+1} 定义一个“成功”子序列的权值为 \sum a_{p_i}”子序列的权值和 \bmod 998244353 $$
Solution: 我们先考虑n个数里选k个数的方案数f(n,k) = C(n-k+1,k) ; 然后我们考虑环上的在链上是$a_1,a_n$可以选但环上不行所以把$a_1,a_n$刨出去=F(n,k) = f(n - 3, k - 1); 然后我们算一个G(n,k,i)表示n个数选k个不连续且必须选I的方案数 if(i <= 0) return 0 ; if(i == 1) return F(n,k) + f(n-4,k-2)  ; if(i > 1) rrturn F(n,k) + G(n-4,k-2,i-2) ; if(i > n / 2) G(n,k,n-i+1) 740422015 ~~~  #include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 3e5 + 7; ll farc[maxn], inv[maxn];   const int mod = 998244353; ll qpow(ll a, ll b = mod - 2) {     ll ans = 1;     for (; b; b >>= 1, a = a * a % mod)         if (b & 1)             ans = ans * a % mod;     return ans; } void prework(int n = 3e5) {     farc[0] = 1;     for (int i = 1; i <= n; i++)         farc[i] = farc[i - 1] * i % mod;     inv[n] = qpow(farc[n]);     inv[0] = 1;     for (int i = n - 1; i >= 1; i--)         inv[i] = inv[i + 1] * (i + 1) % mod; }   ll C(int n, int m) {     if (m > n || m < 0)         return 0;       return farc[n] * inv[m] % mod * inv[n - m] % mod; }   ll f(ll n, ll k) {     return C(n - k + 1, k); }   ll F(ll n, ll k) {     if (n < 3)         return k == 1;     else         return f(n - 3, k - 1); } ll sf[maxn]; ll G(ll n, ll k, ll i) {     if (i > ceil((double)n / 2.0))         return G(n, k, n - i + 1);       if (i <= 0)         return 0;     if (i == 1)         return (F(n, k) + f(n - 4, k - 2)) % mod;     return (sf[i >> 1] + G(n - ((i >> 1) << 2), k - ((i >> 1) << 1), i & 1)) % mod; } int n, k, d; ll a[maxn]; int main() {     prework();       cin >> n >> k >> d;     ll ans = 0;       for (int i = 1; i <= n; i++)     {         sf[i] = (sf[i - 1] + F(n - ((i - 1) << 2), k - ((i - 1) << 1))) % mod;     }       for (int i = 1; i <= n; i++)     {         cin >> a[i];         ans += G(n, k, i) * a[i] % mod;         ans %= mod;     }     cout << ans;     return 0; } ~~~

标签:ch,return,Noip,int,ll,元素,34,序列,模拟
From: https://www.cnblogs.com/guier/p/16725197.html

相关文章

  • C语言:求1/2,2/3,3/5,5/8,8/13,13/21,21/34...前20项和
    #include<stdio.h>//求1/2,2/3,3/5,5/8,8/13,13/21,21/34...前20项和main(){inta,c=1;doublesum=0,b=1.0,d,e,f=1,g=2;for(a=1;a<=20;a++){......
  • [NOIP2021] 方差
    首先考虑\(V[X]=E[X^2]-E[X]^2\),答案可以化作:\[n\sum_{i=1}^na^i-(\sum_{i=1}^na_i)^2\]然后观察操作,进行一次操作本质上是交换了差分序列中相邻两个数,也就是说我......
  • CSP-S模拟赛7
    T1.序列问题盯了T1二十分钟,发现只会\(O(n!)\)的暴力,于是溜了。最后一小时想到了\(O(n^2)\)的dp,拿到了(骗到)50分,而且因为我的dp定义比较原始,所以没有办法优化。首先定义\(b......
  • 25th-27th 2022/7/28,2022/7/29,2022/7/30 模拟赛总结15-17
    首先这次是补,因为有个垃圾将我的总结删了它的名字不配出现在我的总结中这三次其实都不算好主要问题是没睡好,读题不仔细以及并没有拼尽全力去打这几点总结应该注重休......
  • 29th 2022/8/1 模拟赛总结18
    这次还行因为这次认真去打,而且在打T2两个钟时,仍旧能坚持下去,最好迎来了胜利不错的,但仍旧有一些不足在T2打完发现过了时,心花怒放,光顾着打暴力,结果没什么分,T1也没有静心......
  • 30th 2022/8/3 模拟赛总结19
    这次不是很烂,但是问题出现我的思路过于繁复,其实就是对前缀和的概念理解出了问题前缀和不一定是形如\(f_r-f_{l-1}\)只要加减的东西有意义,就可以了如\(f_{i,j}-f_{i-1......
  • 31st 2022/8/4 模拟赛总结20
    这次死在了小错误上虽然并没有考砸,但是本来可以考得更好T1想到了正解但是又是一个小问题断送了前程在求答案时,小数据还好,但是大数据。。。总之,就是在求答案是加上了......
  • 20th 2022/7/18 模拟赛总结12
    这次嗯,题目真是没有半点水分,干巴巴一片T1T3省选模拟,T2NOIP,恐怖的是T4???这次估计上紫赛时T1-T4-T2-T3首先读题很久,30min过,然后着手T1,找规律,没有半分,只用仅有的数论知识......
  • 16th 2022/7/14 模拟赛总结9
    这次哈,没有想打的意思,随便打了两个暴力和一个表就发呆了今天讲一个专题,却听不下去,因为讲题者太帅了,根本听不懂,感觉他就是把课件念了一遍然后回到座位,却还在看讲题,嗯最后......
  • 18th 2022/7/15 模拟赛总结10
    这次哈,依然不大想打随便一打,却发现排名居然没掉,其他人摸鱼吗?其实这次比赛题质量不算很高T1是优化,T2是优化+细节,T3是打过类似的找循环,T4是DP优化嗯,因为要回去了所以没......