CF1515
CF1515
Phoenix and Gold
非常好随机化 爱来自
显然如果我们随机一下序列,有概率让整个数组满足这种情况的。
实测随机
下面是正解:
一个很玄学的思路,我们从前往后扫一遍数组,遇到前缀和不合法的,就交换
如果到最后前缀和不能为
随机化
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 1e2 + 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 , x , a[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read() , x = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
int flgg = 0;
for ( int i = 1 ; i <= 6 ; i ++ )
{
random_shuffle ( a + 1 , a + n + 1 );
int sum = 0 , flag = 1;
for ( int j = 1 ; j <= n ; j ++ )
{
sum += a[j];
if ( sum > x ) break;
if ( sum == x ) { flag = 0; break; }
}
if ( flag ) { flgg = 1; break; }
}
if ( flgg )
{
cout << "YES" << endl;
for ( int i = 1 ; i <= n ; i ++ ) cout << a[i] << ' ';
cout << endl;
}
else cout << "NO" << endl;
}
return 0;
}
正解:
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 1e2 + 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 , x , a[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read() , x = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
int sum = 0;
for ( int i = 1 ; i <= n ; i ++ )
{
if ( sum + a[i] == x ) swap ( a[i] , a[n] );
sum += a[i];
}
if ( sum != x )
{
cout << "YES" << endl;
for ( int i = 1 ; i <= n ; i ++ ) cout << a[i] << ' ';
cout << endl;
}
else cout << "NO" << endl;
}
return 0;
}
Phoenix and Puzzle
基础的正方形为两个或者四个,而且可以证明要么是两个要么是四个,不能同时使用两种类型的基础正方形,否则无法使边长相等。
那么如果
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 1e2 + 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 , x , a[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read();
int flag = 0;
if ( ! ( n % 2 ) )
{
if ( n / 2 == (int)sqrt(n/2) * (int)sqrt(n/2) ) flag = 1;
}
if ( ! ( n % 4 ) )
{
if ( n / 4 == (int)sqrt(n/4) * (int)sqrt(n/4) ) flag = 1;
}
cout << ( flag ? "YES" : "NO" ) << endl;
}
return 0;
}
Phoenix and Towers
一开始用优先队列维护整个序列中的合并情况,发现很不好统计,打出来 WA 了几发。
正难则反,我们可以用优先队列维护整个序列中的
因为保证了每一个数都
那么为最低的塔高
所以这样证明了原题没有无解的情况。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 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 , m , x , a[N] , vis[N] , cnt , ans[N];
vector<int> vec;
struct node { int id , val; friend bool operator < ( const node &a , const node &b ) { return a.val > b.val; } };
priority_queue < node > q;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
while ( !q.empty() ) q.pop();
n = read() , m = read() , x = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 ; i <= m ; i ++ ) q.push({i,0});
for ( int i = 1 ; i <= n ; i ++ )
{
node u = q.top(); q.pop();
ans[i] = u.id;
u.val += a[i];
q.push(u);
}
cout << "YES" << endl;
for ( int i = 1 ; i <= n ; i ++ ) cout << ans[i] << ' ';
cout << endl;
}
return 0;
}
Phoenix and Socks
首先 我们先将所有能匹配上的袜子进行配对,这样是绝对不劣的。
其次我们严格让左面的袜子多,方便我们进行处理,统计
那么我们首先期望要用每次
只要左面点有袜子的数量
注意特判奇数和
对于最后的局面,我们直接让左面袜子和右面袜子用
如果
时间复杂度
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#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 , l , r , a[N] , b[N] , ans;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
n = read() , l = read() , r = read();
memset ( a , 0 , sizeof a );
memset ( b , 0 , sizeof b );
ans = 0;
for ( int i = 1 ; i <= l ; i ++ ) ++ a[read()];
for ( int i = l + 1 ; i <= n ; i ++ ) ++ b[read()];
for ( int i = 1 ; i <= n ; i ++ )
{
if ( a[i] >= b[i] ) a[i] -= b[i] , b[i] = 0;
else if ( a[i] < b[i] ) b[i] -= a[i] , a[i] = 0;
}
// for ( int i = 1 ; i <= n ; i ++ ) cout << a[i] << ' ' << b[i] << endl;
int cntl = 0 , cntr = 0;
for ( int i = 1 ; i <= n ; i ++ ) cntl += a[i] , cntr += b[i];
if ( cntl < cntr )
{
for ( int i = 1 ; i <= n ; i ++ ) swap ( a[i] , b[i] );
swap ( cntl , cntr );
}
for ( int i = 1 ; i <= n ; i ++ )
{
if ( a[i] >= 2 )
{
if ( a[i] > ( cntl - cntr ) ) ans += ( cntl - cntr ) / 2 , cntl = cntr;
else ans += a[i] / 2 , cntl -= a[i] / 2 * 2;
}
if ( cntl == cntr ) break;
}
if ( cntl == cntr ) cout << ans + ( cntl + cntr ) / 2 << endl;
else cout << ans + ( cntl + cntr ) / 2 + ( cntl - cntr ) / 2 << endl;
}
return 0;
}
Phoenix and Computers
一类很新的
设
有三类操作。
-
将某一个块的元素数量
那么每一个块都有可能
,所以 。 -
新增一个块
类似插空的方法,因为对于
,有 个块,那么显然有 个空位可以插入。所以
。 -
合并两个块
类似第二种类操作 只不过我们从
个块向 个块进行推导。显然有
。
这些是这类
对于本题,也是依照上面的操作来推导。
-
新增一个元素
可以发现有两种情况:
- 直接加入,此时
。 - 隔一个加入,这样又有一个会自动生成,此时
。
注意,下面的乘二都是因为一个块可以在左面或者右面加入。
- 直接加入,此时
-
新增一个块
直接加即可,
。 -
合并两个块
也有两种情况:
- 在两个块中间隔着两个,这种情况可以任意在某一边去加一个元素,
。 - 在两个块中间隔着三个,这种情况我们可以在中间加一个元素,
- 在两个块中间隔着两个,这种情况可以任意在某一边去加一个元素,
这样我们将上述五种转移统一起来就做完了。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
#define int long long
const int N = 1e3 + 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 , mod , f[N][N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , mod = read();
f[1][1] = 1;
for ( int i = 2 ; i <= n ; i ++ )
for ( int j = 1 ; j <= n ; j ++ )
{
if ( i > 1 ) f[i][j] += f[i-1][j-1] * j;
if ( i > 1 ) f[i][j] += f[i-1][j] * j * 2;
if ( i > 2 ) f[i][j] += f[i-2][j] * j * 2;
if ( i > 2 ) f[i][j] += f[i-2][j+1] * j * 2;
if ( i > 3 ) f[i][j] += f[i-3][j+1] * j;
f[i][j] %= mod;
}
cout << f[n][1] << endl;
return 0;
}
Phoenix and Earthquake
我们考虑一个很显然的结论:如果
那么我们尝试证明:如果不满足上面这个条件的生成树一定有解。
可以用归纳证明:
- 如果
那么我们可以先将 和 连边 这样就转化为了 个点的情况 - 如果
那么我们可以将这条边先行删除 留待最后再加 这样也转化为 个点的情况 并且因为目标式子右面减掉了 而左面减掉了一个 的 那么原式仍然符合条件
那么我们遍历图并按照上述操作维护操作序列即可
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define pii pair<int,int>
#define fi first
#define se second
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
#define int long long
const int N = 3e5 + 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 , fa[N] , sum , a[N] , x , ans[N] , head , tail;
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
struct Dsu
{
void init() { for ( int i = 1 ; i <= n ; i ++ ) fa[i] = i; }
int find ( int u ) { return fa[u] == u ? u : fa[u] = find(fa[u]); }
}D;
void dfs ( int u , int ff , int id )
{
for ( auto p : e[u] )
{
int v = p.fi , w = p.se;
if ( v ^ ff ) dfs ( v , u , w );
}
if ( u == 1 ) return;
if ( a[u] >= x ) a[ff] += a[u] - x , ans[++head] = id;
else ans[--tail] = id;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = tail = read() , m = read() , x = read();
D.init();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , sum += a[i];
for ( int i = 1 , u , v ; i <= m ; i ++ )
{
u = read() , v = read();
int fu = D.find(u) , fv = D.find(v);
if ( fu == fv ) continue;
fa[fv] = fu;
add ( u , v , i ) , add ( v , u , i );
}
for ( int i = 1 ; i <= n ; i ++ ) if ( D.find(i) != D.find(1) ) return cout << "NO" << endl , 0;
if ( sum < x * ( n - 1 ) ) return cout << "NO" << endl , 0;
dfs ( 1 , 0 , 0 ) , cout << "YES" << endl;
for ( int i = 1 ; i < n ; i ++ ) cout << ans[i] << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!