2022牛客多校第二场CDE
Posted 吃花椒的妙酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022牛客多校第二场CDE相关的知识,希望对你有一定的参考价值。
C题
题意:nim游戏,先手赢的话,尽量赢的快,输的话尽量输的慢。
求最多的游戏局数,和先手执行的最优策略数
下面给两个结论:
1,石子数异或和为0的话,先手败,否则胜
2,先手败的话,可以构造出先后手后面都只取一个石子。
结论1证明略。
下证结论2
先手必败,也就是说xor_sum=0
先考虑构造游戏局数尽量多的方案,先手在lowbit最小的石子堆里取一个。
后手只能对称地在另一个lowbit相等的堆里取一个。比如先手取的是…100,取完后变成了…011,xor_sum->xor_sum^(111),后手必须构造出(111)抵消掉影响。如果后手选lowbit大于先手lowbit的堆,那么会对更高位造成影响。所以后手只能选lowbit的石子堆,取一个石子。也就是说这样后手是和先手对称着操作的,对称着去lowbit相等的石子堆。
上面构造出一种方案,使得总局数为sum,再考虑上面情况下先手第一步取的方案数
再理一下条件,现在先手只能取一个,要使得后手也只能取一个。我们考虑什么情况下,后手可以多取。设先手取的石子堆lowbit是第i位,若存在另一堆第i位为1且i不为lowbit,则后手可以多取。比如先手取10100,存在00110,先手取后xor_sum->xor_sum^(111),后手可以把两个1都取掉抵消掉(111)的影响。
其他情况:
1,第i位为0,那么怎么操作到无法抵消掉先手造成的对第i位的影响。
2,第i位为1且为lowbit,那后手只能对称取一个石子。。。
证毕(乱证)
下面考虑先手胜,那第一步要尽可能取多,且使得剩下异或和为0。怎么求最大取掉多少呢。
设原异或和为S,要从ai中选t个石子取掉,剩下异或和0.
先扣除掉ai,则异或和为S^ai,只要ai>(S ^ ai)则存在,t = ai - (S ^ ai),使得S ^ (ai -t)=0.
维护t和次数即可。
很nb的思考题!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ios ios::sync_with_stdio(false),cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pii pair<int ,int >
#define pb(v) push_back(v)
#define all(v) v.begin(),v.end()
#define int long long
#define inf 0x3f3f3f3f
#define INF 0x7f7f7f7f7f7f7f7f
#define endl "\\n"
#define fi first
#define se second
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define AC return 0
#define ldb long double
const int N=5e5+5;
const int mod=1e9+7;
const double eps=1e-8;
int n;
int a[N];
map<int,int> mp;
void solve()
cin>>n;
int x_sum=0,sum=0;
_for(i,1,n)
cin>>a[i];
x_sum ^= a[i];
sum += a[i];
if( !x_sum )
int cnt=0;
_for(i,1,n) mp[a[i]&-a[i]] = 0;
_for(i,1,n)
int t = a[i];
t -= t&-t;
while( t )
mp[t&-t]=1;
t -= t&-t;
_for(i,1,n) if( !mp[a[i]&-a[i]] ) cnt++;
cout<<sum<<" "<<cnt<<endl;
else
int mx = 0,cnt=0;
_for(i,1,n)
if( a[i] > (a[i]^x_sum) )
int t = a[i] - (a[i]^x_sum);
if( t > mx )
mx = t;
cnt=1;
else if( mx == t ) cnt++;
cout<<sum-mx+1<<" "<<cnt<<endl;
signed main()
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
IOS;
int T;cin>>T;
while(T--) solve();
AC;
D题
题意:给n个物品间的兑换关系(n<=1e3),兑换关系如下a个x可以换wb个y,其中w是要求的,求最大的w,使得这些物品不能够无限制兑换。(无限制兑换指1个x换2个y,1个y能换10个x,这样可以无限兑换)
做法:考虑建图,二分w,然后check,边权为汇率,由于乘积很大,边权取个对,然后就是判有没有正环
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pii pair<int ,int >
#define pb(v) push_back(v)
#define all(v) v.begin(),v.end()
#define int long long
#define inf 0x3f3f3f3f
#define INF 0x7f7f7f7f7f7f7f7f
#define endl "\\n"
#define fi first
#define se second
#define ls p<<1
#define rs p<<1|1
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
#define AC return 0
#define double long double
const int N=1e3+5;
const int mod=1e9+7;
const double eps=1e-8;
int n,m;
int vis[N],cnt[N];
double dis[N];
std::vector< pair<int,double> > G[N];
queue<int> q;
bool ck(double mid,int st)//就是spaf求最短路
mst(dis,0);
mst(cnt,0);
queue<int> q;
_for(i,1,n)
q.push(i);
vis[i]=1;
while( !q.empty() )
int x = q.front();q.pop();
vis[x] = 0;
for(auto [y,len] :G[x])
if( dis[x] + len + mid > dis[y] )
dis[y] = dis[x] + len + mid;
cnt[y]++;
if( cnt[y] >= n ) return 0;
if( !vis[y] )
vis[y] = 1;
q.push(y);
return 1;
signed main()
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
// IOS;
cin>>n>>m;
_for(i,1,m)
int b,d;
double a,c;
cin>>a>>b>>c>>d;
G[b].push_back( d,log2(c) - log2(a));
double l = 0 , r = 1;
_for(i,1,50)
double mid = (l+r)/2;
if( ck(log2(mid),1) ) l = mid;
else r = mid;
printf("%.8Lf\\n",r);
AC;
e题
题意:求长为n,含k个“bit”的字符串数,输出k从0到n的方案数,n<=1e6
做法:二项式反演+差卷积
考虑容斥,设
G
k
G_k
Gk表示含k个bit的方案数,
F
k
F_k
Fk为至少含k个bit的方案数
F
k
=
C
n
−
2
k
k
∗
(
2
6
n
−
3
k
)
F_k=C_n-2k^k*(26^n-3k)
Fk=Cn−2kk∗(26n−3k)
G
k
=
∑
j
=
k
n
(
−
1
)
j
−
k
∗
C
j
k
F
j
G_k=\\sum_j=k^n(-1)^j-k*C_j^kF_j
Gk=∑j=kn(−1)j−k∗CjkFj,组合数展开后分离系数
k
!
∗
G
k
=
∑
j
=
k
n
(
j
!
F
j
)
∗
(
−
1
)
j
−
k
(
j
−
k
)
!
k!*G_k = \\sum_j=k^n(j!F_j)*\\frac(-1)^j-k(j-k)!
k!∗Gk=∑j=kn(j!Fj)∗(j−k)!(−1)j−k
发现右边是差卷积形式,翻转其中一个多项式后求卷积即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(以上是关于2022牛客多校第二场CDE的主要内容,如果未能解决你的问题,请参考以下文章
2022牛客多校第四场C.Easy Counting Problem(EGF+NTT)