[AtCoder Regular Contest 125] A-F全题解
文章目錄
- A - Dial Up
- B - Squares
- C - LIS to Original Sequence
- D - Unique Subsequence
- E - Snack
- F - Tree Degree Subset Sum
網址鏈接
A - Dial Up
簽到題
特判一下有沒有0/1在目標串中出現而沒在原串出現
除了第一次0/1數字互換時,需要從a1a_1a1?左右找距離最近的不同數字
后面互換就是左/右轉一次
#include <cstdio> #include <iostream> using namespace std; #define maxn 200005 int n, m; bool s0, s1, t0, t1; int s[maxn], t[maxn];int main() {scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &s[i] );if( s[i] ) s1 = 1;else s0 = 1;}for( int i = 1;i <= m;i ++ ) {scanf( "%d", &t[i] );if( t[i] ) t1 = 1;else t0 = 1;}if( ( t1 and ! s1 ) or ( t0 and ! s0 ) )return ! printf( "-1\n" );int l = 0, r = 0;for( int i = n;i;i -- )if( s[i] == s[1] ) l ++;else { l ++; break; }for( int i = 1;i <= n;i ++ )if( s[i] == s[1] ) r ++;else break;int c = min( l, r ), now = s[1], ans = 0;bool flag = 0;for( int i = 1;i <= m;i ++ ) {if( now ^ t[i] ) {if( flag ) now ^= 1, ans ++;else now ^= 1, ans += c;flag = 1;}ans ++;}printf( "%d\n", ans );return 0; }B - Squares
簡單題
x2?y=z2(x,y∈[1,n])x^2-y=z^2\quad \Big(x,y\in[1,n]\Big)x2?y=z2(x,y∈[1,n])
(x+z)(x?z)=y(x+z)(x-z)=y(x+z)(x?z)=y
observation : x+z x-z 同奇偶,且x+z >>> x-z
則有 x?z∈[1,n]x-z\in[1,\sqrt{n}]x?z∈[1,n?]
考慮枚舉i=x?zi=x-zi=x?z,計算出x+zx+zx+z的范圍[1,?ni?]\big[1,\lfloor\frac{n}{i}\rfloor\big][1,?in??]
然后計算在范圍內與iii同奇偶的個數
時間復雜度O(n)O(\sqrt n)O(n?)
#include <cstdio> #include <iostream> using namespace std; #define int long long #define mod 998244353 int n, ans;signed main() {scanf( "%lld", &n );for( int i = 1;i * i <= n;i ++ ) {int l = i, r = n / i;if( ( i & 1 ) ^ ( l ^ 1 ) ) l ++;if( ( i & 1 ) ^ ( r ^ 1 ) ) r ++;if( l <= r ) ans = ( ans + ( r - l ) / 2 + 1 ) % mod;}printf( "%lld\n", ans );return 0; }C - LIS to Original Sequence
簡單構造題
observation1 : a1a_1a1?一定填在序列第一位
-
如果a1=1a_1=1a1?=1,填序列第一位是肯定的
-
如果a1>1a_1>1a1?>1,假設不填第一個,那么需要一個小于a1a_1a1?的數填在前面,才會是最佳字典序
但填在a1a_1a1?前面,就會和a1,...,aka_1,...,a_ka1?,...,ak?構成更長的最長上升子序列,不滿足條件,假設不成立
observation2 : 如果a1≠1a_1≠1a1??=1,則a2a_2a2?一定填111是最優的
- 第一位都已經固定了,為了使答案字典序最小,肯定先放111,構成1,a2,...,ak1,a_2,...,a_k1,a2?,...,ak?的相同長度LIS\rm LISLIS
observation3 : 除去a1a_1a1?和111,出現了新的子問題,構造一個長度為n?2n-2n?2的序列,LIS\rm LISLIS為a2,...,aka_2,...,a_ka2?,...,ak?
所以可以一位一位的遞歸構造,實際上遍歷一遍即可構造
#include <cstdio> #define maxn 200005 int a[maxn]; bool vis[maxn]; int n, k;int main() {scanf( "%d %d", &n, &k );for( int i = 1;i <= k;i ++ ) scanf( "%d", &a[i] );for( int i = 1, j = 1;i < k;i ++ ) {printf( "%d ", a[i] );vis[a[i]] = 1;while( j < a[i] and vis[j] ) j ++;if( ! vis[j] ) printf( "%d ", j ), vis[j] = 1;}for( int i = n;i;i -- )if( ! vis[i] ) printf( "%d ", i );return 0; }D - Unique Subsequence
DPDPDP簡單題
observation : x......x****,x****后面以xxx開頭的任意子序列都不會成為答案
所以可以設計dpi:dp_i:dpi?: 從后往前到i時以iii開始的答案,lstAi:lst_{A_i}:lstAi??: AiA_iAi?上一次的位置
dpi=∑j=i+1lstAidpjdp_i=\sum_{j=i+1}^{lst_{A_i}}dp_jdpi?=∑j=i+1lstAi???dpj? 并且dplstAidp_{lst_{A_i}}dplstAi???要清零
最后答案就是∑idplsti\sum_i dp_{lst_i}∑i?dplsti??
區間求和,單點修改可以用樹狀數組維護
#include <cstdio> #define mod 998244353 #define int long long #define maxn 200005 int n; int f[maxn], t[maxn], lst[maxn], A[maxn];int lowbit( int i ) { return i & -i; }void add( int i, int val ) {for( ;i <= n;i += lowbit( i ) ) t[i] = ( t[i] + val + mod ) % mod; }int query( int i ) {int ans = 0;for( ;i;i -= lowbit( i ) ) ans = ( ans + t[i] ) % mod;return ans; }signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &A[i] );for( int i = n;i;i -- ) {if( ! lst[A[i]] ) f[i] = ( query( n ) + 1 ) % mod;else f[i] = query( lst[A[i]] );if( lst[A[i]] ) add( lst[A[i]], -f[lst[A[i]]] );add( i, f[i] );lst[A[i]] = i; }int ans = 0;for( int i = 1;i <= n;i ++ ) ans = ( ans + f[lst[i]] ) % mod;printf( "%lld\n", ans );return 0; }E - Snack
困難題
一眼網絡流
- 超級源點SSS,超級匯點TTT,蛇Li,i∈[1,n]L_i,i\in[1,n]Li?,i∈[1,n],人Rj,j∈[1,m]R_j,j\in[1,m]Rj?,j∈[1,m]
- ?i,i∈[1,n]S→Li\forall_{i,i\in[1,n]} S\rightarrow L_i?i,i∈[1,n]?S→Li?,流量AiA_iAi?
- ?i,i∈[1,n];j,j∈[1,m]Li→Rj\forall_{i,i\in[1,n];j,j\in[1,m]}L_i\rightarrow R_j?i,i∈[1,n];j,j∈[1,m]?Li?→Rj?,流量BjB_jBj?
- ?j,j∈[1,m]Rj→T\forall_{j,j\in[1,m]}R_j\rightarrow T?j,j∈[1,m]?Rj?→T,流量CjC_jCj?
求圖的最大流即可
但是n,mn,mn,m級別根本不能支持網絡流的算法
需要找一種可以不真的跑網絡流的算法求最大流
轉換一下,最大流等于最小割
將蛇LiL_iLi?分成X,YX,YX,Y兩個部分,XXX與超級源點在一個集合,YYY與超級匯點在一個集合
則每個人RjR_jRj?就可以獨立決定自己是在SSS集合還是TTT集合
- 在SSS集合,就要斷掉和TTT的邊,花費CjC_jCj?
- 在TTT集合,就要斷掉和XXX集合的所有邊,花費集合大小的∣X∣?Bj|X|·B_j∣X∣?Bj?
- 選擇兩者中的較小值
重要的是XXX的劃分,因此先決定XXX的劃分
按AiA_iAi?的降序從LiL_iLi?中選擇用作XXX的定點
嘗試所有的XXX,從0?N0-N0?N
F - Tree Degree Subset Sum
困難題
令did_idi?表示iii點的度數?1-1?1,則度數范圍為[0,n?2][0,n-2][0,n?2]
定義fif_ifi? : 度數和為iii時最小選取頂點的集合個數,gig_igi? : 度數和為iii時最大選取頂點的集合個數
引理:?fi≤y≤gi\forall_{f_i\le y\le g_i}?fi?≤y≤gi??,一定都有一種頂點選取方式滿足度數和為yyy
假設這個引理是正確的
利用與abc-215 colorful candies 2的同樣的思想
不同度數的個數最多有n\sqrt nn?
設計DPDPDP轉移出fif_ifi?,ggg可以由fff推出
fi=min?{fi?sumd+cnt}f_i=\min\{f_{i-sumd}+cnt\}fi?=min{fi?sumd?+cnt}
可以用log\rm loglog倍增一段相同度數個數
最后gig_igi?就相當于總個數減去度數和為s?is-is?i的最小選取頂點的集合個數fs?if_{s-i}fs?i?
#include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std; #define maxn 200005 #define int long long struct node { int sumd, cnt;node(){}node( int Sumd, int Cnt ) {sumd = Sumd, cnt = Cnt;} }; vector < node > g; int n; int d[maxn], f[maxn];signed main() {scanf( "%lld", &n );memset( d, -1, sizeof( d ) );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );d[u] ++, d[v] ++;}sort( d + 1, d + n + 1 );for( int i = 1, j = 1;i <= n;i = j ) {while( j <= n and d[i] == d[j] ) j ++;int cnt = j - i;for( int k = 1;k <= cnt;k <<= 1 ) {g.push_back( node( d[i] * k, k ) );cnt -= k;}if( cnt ) g.push_back( node( d[i] * cnt, cnt ) );}memset( f, 0x3f, sizeof( f ) );f[0] = 0; int sum = 0;for( auto now : g ) {sum += now.sumd;for( int i = sum;i >= now.sumd;i -- )f[i] = min( f[i], f[i - now.sumd] + now.cnt );}int ans = 0;for( int i = 0;i <= sum;i ++ )ans += max( ( n - f[sum - i] ) - f[i] + 1, 0ll );printf( "%lld\n", ans );return 0; }總結
以上是生活随笔為你收集整理的[AtCoder Regular Contest 125] A-F全题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 听说人看到自己喜欢的人时瞳孔会变大这是什
- 下一篇: Windows系统怎么输入特殊符号?