CF1343
Candies
相当于是 \((1<<k)-1=\frac{n}{x}\) 那么我们枚举合法的 \(k\) 即可
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+r>>1)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
#define int unsigned int
const int N = 2e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , ans;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read() , ans = 0;
for ( int k = 4 ; k - 1 <= n ; k <<= 1 )
if ( n % ( k - 1 ) == 0 ) { ans = n / ( k - 1 ); break; }
cout << ans << endl;
}
return 0;
}
Balanced Array
如果长度 \(mod\ 4\neq 0\) 那么无解 因为此时左右的奇偶性一定不相同
显然我们可以暴力将 \(1-n\) 中的奇偶数填进去 对于最后一个奇数特判一下就好
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+r>>1)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
#define int unsigned int
const int N = 2e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , ans;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
if ( n % 4 == 0 && n >= 4 )
{
cout << "YES" << endl;
for ( int i = 1 ; i <= n / 2 ; i ++ )
cout << i * 2 << ' ';
for ( int i = 1 ; i < n / 2 ; i ++ )
cout << i * 2 - 1 << ' ';
cout << n - 1 + n / 2 << endl;
}
else cout << "NO" << endl;
}
return 0;
}
Alternating Subsequence
一开始看成了连续的子序列 导致过不去样例()
因为我们需要最长 所以我们对于每一个正负相同的连续段 都需要选取最大的一个数 累加即可
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+r>>1)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
#define int long long
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , a[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
int sum = 0 , maxx = -inf , op = -1;
for ( int i = 1 ; i <= n ; i ++ )
{
a[i] = read();
if ( op == -1 )
{
maxx = max ( maxx , a[i] );
op = ( a[i] > 0 );
}
else if ( op == 0 )
{
if ( a[i] < 0 ) maxx = max ( maxx , a[i] );
else sum += maxx , op = 1 , maxx = a[i];
}
else
{
if ( a[i] > 0 ) maxx = max ( maxx , a[i] );
else sum += maxx , op = 0 , maxx = a[i];
}
}
cout << sum + ( maxx == -inf ? 0 : maxx ) << endl;
}
return 0;
}
Constant Palindrome Sum
显然我们有 \(O(nk)\) 的暴力 即枚举最终的目标状态并判断是否能达到
考虑优化 设 \(swap0[i]\) 和 \(swap1[i]\) 和 \(swap2[i]\) 分别表示目标为 \(i\) 的时候 需要改 \(0/1/2\) 次的点对个数
\(0\) 次非常显然 直接枚举所有点对并标记即可
\(1\) 次 我们可以修改上面的定义 即 \(swap1[i]\) 表示至多修改一次的代价 直接将 \(min(a[i],a[n-i+1])+1\) 和 \(max(a[i],a[n-i+1])+k\) 之间的所有点标记 \(+1\) 即可 这个可以用差分数组实现
对于 \(2\) 次 即为 \(swap2[i]=\frac n 2 -swap1[i]\)
最后计入答案即为 \(swap2[i] \times 2 + swap1[i] - swap0[i]\)
\(O(nk)\):
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+r>>1)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , k , a[N] , ans;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
ans = inf;
n = read() , k = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int aim = 1 ; aim <= k * 2 ; aim ++ )
{
int res = 0;
for ( int i = 1 ; i <= n / 2 ; i ++ )
{
if ( a[i] + a[n-i+1] == aim ) res += 0;
else if ( ! ( a[i] + 1 <= aim && aim <= a[i] + k || a[n-i+1] + 1 <= aim && aim <= a[n-i+1] + k ) ) res += 2;
else ++ res;
}
ans = min ( res , ans );
}
cout << ans << endl;
}
return 0;
}
\(O(n)\) 正解:
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+r>>1)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , k , a[N] , ans , swap0[N] , swap1[N] , swap2[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
ans = inf;
n = read() , k = read();
fill ( swap0 + 1 , swap0 + 2 * k + 1 , 0 );
fill ( swap1 + 1 , swap1 + 2 * k + 1 , 0 );
fill ( swap0 + 1 , swap2 + 2 * k + 1 , 0 );
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 ; i <= n / 2 ; i ++ ) ++ swap0[a[i]+a[n-i+1]];
for ( int i = 1 ; i <= n / 2 ; i ++ ) swap1[min(a[i],a[n-i+1])+1] ++ , swap1[max(a[i],a[n-i+1])+k+1] --;
for ( int i = 1 ; i <= 2 * k ; i ++ ) swap1[i] += swap1[i-1];
for ( int i = 1 ; i <= 2 * k ; i ++ ) swap2[i] = n / 2 - swap1[i] , ans = min ( ans , swap1[i] - swap0[i] + swap2[i] * 2 );
cout << ans << endl;
}
return 0;
}
Weights Distributing
对于两个点 \(a,b\) 显然有一个贪心:我们求出 \(a,b\) 之间的最短路 并将所有最小的边贪心地填进去
但是这样对于三个点是不成立的:因为我们有可能出现 \(a,b\) 的最短路和 \(b,c\) 的最短路重复的情况
那么我们考虑答案路径: \(a\rightarrow i\rightarrow b\rightarrow i\rightarrow c\) 那么我们枚举中间的 \(i\) 节点 进行起点为 \(a,b,c\) 的三次 \(bfs\) 并组合答案即可
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+r>>1)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
#define int long long
const int N = 4e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , m , w[N] , dis[3][N] , sum[N] , a , b , c , vis[N] , ans;
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void bfs ( int s , int op )
{
fill ( vis + 1 , vis + n + 1 , 0 );
queue<int> q; q.push(s) , vis[s] = 1;
while ( !q.empty() )
{
int u = q.front(); q.pop();
for ( auto v : e[u] ) if ( !vis[v] ) dis[op][v] = dis[op][u] + 1 , vis[v] = 1 , q.push(v);
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
ans = inf;
n = read() , m = read() , a = read() , b = read() , c = read();
for ( int i = 1 ; i <= n ; i ++ ) e[i].clear();
for ( int i = 0 ; i <= 2 ; i ++ ) for ( int j = 1 ; j <= n ; j ++ ) dis[i][j] = 0;
generate ( w + 1 , w + m + 1 , read );
sort ( w + 1 , w + m + 1 );
partial_sum ( w + 1 , w + m + 1 , sum + 1 );
for ( int i = 1 , u , v ; i <= m ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
bfs ( a , 0 ) , bfs ( b , 1 ) , bfs ( c , 2 );
for ( int i = 1 ; i <= n ; i ++ ) if ( dis[0][i] + dis[1][i] + dis[2][i] <= m ) ans = min ( ans , sum[dis[0][i] + dis[1][i] + dis[2][i]] + sum[dis[1][i]] );
cout << ans << endl;
}
return 0;
}
Restore the Permutation by Sorted Segments
很奇妙的构造
我们可以先枚举第一位填什么 然后向后枚举所有限制 看能否满足
对于我们枚举的每一位 我们都枚举所有的限制和限制中的每一位数 如果这条限制只剩这一个数且这条限制其他的数位置都在区间内 那么是合法的 填写进去
否则直接开始枚举第一位的下一个数即可
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+r>>1)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 2e2 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , ans[N] , pos[N] , a[N][N];
int pd ()
{
for ( int i = 2 ; i <= n ; i ++ )//枚举每一位
{
for ( int j = 1 ; j < n ; j ++ )
{
int lim = a[j][0] , x = -1;
for ( int k = 1 ; k <= a[j][0] ; k ++ )
{
int now = a[j][k];
if ( !pos[now] ) x = now;
else if ( pos[now] >= i - a[j][0] + 1 ) lim --;
}
if ( lim == 1 && x != -1 )
{
ans[i] = x , pos[x] = i;
break;
}
}
if ( !ans[i] ) return 0;
}
return 1;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
for ( int i = 1 ; i < n ; i ++ )
{
a[i][0] = read();
for ( int j = 1 ; j <= a[i][0] ; j ++ ) a[i][j] = read();
}
for ( int i = 1 ; i <= n ; i ++ )
{
for ( int j = 1 ; j <= n ; j ++ ) ans[j] = pos[j] = 0;
ans[1] = i , pos[i] = 1;
if ( pd() ) break;
}
for ( int i = 1 ; i <= n ; i ++ ) cout << ans[i] << ' ';
cout << endl;
}
return 0;
}