CF1454
CF1454
Special Permutation
直接错开输出即可
#include <bits/stdc++.h>
using namespace std;
#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 = (1<<16) + 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;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
int n = read();
for ( int i = 1 ; i < n ; i ++ ) cout << i + 1 << ' ';
cout << 1 << endl;
}
return 0;
}
Unique Bid Auction
开桶模拟即可
#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 cnt[N] , a[N] , n , pos[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
memset ( pos , inf , sizeof pos );
memset ( cnt , 0 , sizeof cnt );
generate ( a + 1 , a + n + 1 , read );
for ( int i = 1 ; i <= n ; i ++ ) ++ cnt[a[i]] , pos[a[i]] = min ( pos[a[i]] , i );
int flag = 0;
for ( int i = 1 ; i <= n ; i ++ ) if ( cnt[i] == 1 ) { flag = 1 , cout << pos[i] << endl; break; }
if ( flag == 0 ) cout << -1 << endl;
}
return 0;
}
Sequence Transformation
容易发现连续的相等段是没有用的 那么我们可以先缩一下
分类讨论 设一个值 \(i\) 的出现次数 \(cnt[i]\)
- 如果这个值 \(i\) 在头尾都出现 那么计入答案为 \(cnt[i]-1\)
- 如果只在头或尾出现 那么计入答案为 \(cnt[i]\)
- 否则为 \(cnt[i]+1\)
#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 cnt[N] , a[N] , b[N] , tot , n , ans;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
memset ( cnt , 0 , sizeof cnt ) , tot = 0 , ans = inf;
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 ; i <= n ; i ++ ) if ( a[i] != a[i-1] ) b[++tot] = a[i] , ++ cnt[a[i]];
for ( int i = 1 ; i <= n ; i ++ )
if ( cnt[i] )
{
if ( b[1] == i && b[tot] == i ) ans = min ( ans , cnt[i] - 1 );
else if ( b[1] == i || b[tot] == i ) ans = min ( ans , cnt[i] );
else ans = min ( ans , cnt[i] + 1 );
}
cout << ans << endl;
}
return 0;
}
Number into Sequence
观察样例可以知道 最终答案一定形如 \(k-1\) 个相等的 \(c\) 和一个 \(n/c^{k-1}\) 其中 \(k\) 为 \(c\) 这个因数在正整数唯一分解中的指数
输出 \(k-1\) 个是因为需要保证最后一个数有 \(c\) 这个因数
#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 = 1e5 + 5;
const int maxn = 1e5 + 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 , cnt;
int prime[N] , isntprime[N] , tot;
void pre ()
{
for ( int i = 2 ; i <= maxn ; i ++ )
{
if ( !isntprime[i] ) prime[++tot] = i;
for ( int j = 1 ; j <= tot && i * prime[j] <= maxn ; j ++ )
{
isntprime[i*prime[j]] = 1;
if ( i % prime[j] == 0 ) break;
}
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
pre();
int T = read();
while ( T -- )
{
n = read() , cnt = 0 , ans = 0;
int temp = n;
for ( int i = 1 ; i <= tot ; i ++ )
{
int tmpcnt = 0;
while ( temp % prime[i] == 0 )
{
temp /= prime[i];
++ tmpcnt;
}
if ( cnt < tmpcnt ) ans = prime[i] , cnt = tmpcnt;
}
int mul = 1;
cout << max ( cnt , 1ll ) << endl;
for ( int i = 1 ; i < cnt ; i ++ ) cout << ans << ' ' , mul *= ans;
cout << n / mul << endl;
}
return 0;
}
Number of Simple Paths
基环树的题 但是 \(*2000\)
我们想如果所有点都在环上 那么答案一定是 \(n*(n-1)\) 因为每一个有序点对存在两条简单路径
现在考虑加上树 那么对于环上的每一个点 \(s_i\) 它和它的子树内部之间的点对都是只有一条简单路径
最后答案即为 \(n*(n-1)-\sum \frac {size_{s_i}(size_{s_i}-1)} 2\)
不要用 \(memset\) 用 \(fill\) 最好
#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;
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 , pos , ff , fa[N] , vis[N] , mark[N] , sz[N] , ans;
vector<int> e[N] , circ;
inl void add ( int u , int v ) { e[u].eb(v); }
void dfs1 ( int u )//?
{
vis[u] = 1;
for ( auto v : e[u] )
{
if ( v == fa[u] ) continue;
if ( vis[v] ) pos = v , ff = u;
else fa[v] = u , dfs1(v);
}
}
void dfs2 ( int u , int ff )
{
sz[u] = 1;
for ( auto v : e[u] )
{
if ( v == ff || mark[v] ) continue;
dfs2 ( v , u );
sz[u] += sz[v];
}
}
void init()
{
circ.clear();
for ( int i = 1 ; i <= n ; i ++ ) e[i].clear();
fill ( vis + 1 , vis + n + 1 , 0 );
fill ( mark + 1 , mark + n + 1 , 0 );
fill ( fa + 1 , fa + n + 1 , 0 );
ans = 0;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
init();
for ( int i = 1 , u , v ; i <= n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
dfs1 ( 1 );
while ( 1 )
{
circ.eb(pos) , mark[pos] = 1;
if ( pos == ff ) break;
pos = fa[pos];
}
for ( auto u : circ ) dfs2 ( u , 0 ) , ans += ( sz[u] - 1 ) * sz[u] / 2;
cout << n * ( n - 1 ) - ans << endl;
}
return 0;
}
Array Partition
显然看到区间最小值想到 \(st\) 表
但是暴力枚举两个分割点是 \(O(n^2)\) 的 考虑优化
发现我们可以先枚举出 \(x\) 端点 对于右端点 因为前缀 \(min\) 是单调不升而后缀 \(max\) 是单调不降的 那么我们二分这个位置看是否能相等即可
调了好一阵()
#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;
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] , aim;
struct ST
{
int maxx[N][25] , minn[N][25];
void build ()
{
for ( int i = 1 ; i <= n ; i ++ ) maxx[i][0] = minn[i][0] = a[i];
for ( int j = 1 ; j <= 20 ; j ++ )
for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
maxx[i][j] = max ( maxx[i][j-1] , maxx[i+(1<<j-1)][j-1] ) , minn[i][j] = min ( minn[i][j-1] , minn[i+(1<<j-1)][j-1] );
}
int qmaxx ( int l , int r )
{
int len = __lg(r-l+1);
return max ( maxx[l][len] , maxx[r-(1<<len)+1][len] );
}
int qminn ( int l , int r )
{
int len = __lg(r-l+1);
return min ( minn[l][len] , minn[r-(1<<len)+1][len] );
}
}st;
int find ( int x , int y )
{
int l = x , r = y;
while ( l <= r )
{
int maxx = st.qmaxx ( mid + 1 , n ) , minn = st.qminn ( x , mid );
// cout << l << ' ' << mid << ' ' << minn << endl;
// cout << mid + 1 << ' ' << r << ' ' << maxx << endl;
if ( aim == maxx && aim == minn ) return mid;
if ( aim >= maxx && aim >= minn ) r = mid - 1;
else if ( aim <= maxx && aim <= minn ) l = mid + 1;
else break;
}
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] = read();
st.build();
int flag = 0;
for ( int i = 1 ; i <= n ; i ++ )
{
aim = st.qmaxx(1,i);
int res = find ( i + 1 , n - 1 );
if ( res != -1 )
{
cout << "YES" << endl , flag = 1;
cout << i << ' ' << res - i << ' ' << n - res << endl;
break;
}
}
if ( !flag ) cout << "NO" << endl;
}
return 0;
}