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的思考题!
#includeusing 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 #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 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< 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< #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,边权为汇率,由于乘积很大,边权取个对,然后就是判有没有正环
#includeusing 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 #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 > G[N]; queue q; bool ck(double mid,int st){//就是spaf求最短路 mst(dis,0); mst(cnt,0); queue 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("%.8Lfn",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
发现右边是差卷积形式,翻转其中一个多项式后求卷积即可。
#includeusing 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 #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 maxn = 6e6+10; const int p = 998244353; int Pow(int x,int d){ int tans = 1; if(d == 0)return 1%p; int a = Pow(x,d/2); tans = 1ll*a*a%p; if(d%2)tans = 1ll*tans*x%p; return tans%p; } typedef vector Poly;//多项式定义 int F1[maxn],F2[maxn]; int rev[maxn]; void NTT(int * A,int lim,int opt) { int i, j, k, m, gn, g, tmp; for(int i = 0; i < lim; ++i)rev[i] = (i & 1)*(lim >> 1) + (rev[i >> 1] >> 1); for(i = 0; i < lim; ++i)if (rev[i] < i) swap(A[i], A[rev[i]]); for(m = 2; m <= lim; m <<= 1) { k = m >> 1; gn = Pow(3,(p - 1) / m); for(i = 0; i < lim; i += m) { g = 1; for (j = 0; j < k; ++j, g = 1ll * g * gn % p) { tmp = 1ll * A[i + j + k] * g % p; A[i + j + k] = (A[i + j] - tmp + p) % p; A[i + j] = (A[i + j] + tmp) % p; } } } if(opt == -1){ reverse(A+1,A+lim); int inv = Pow(lim,p-2); for(i = 0; i < lim; ++i) A[i] = 1ll * A[i] * inv % p; } } Poly mul(const Poly & A,const Poly & B){ int n = A.size(),m = B.size(); int siz = n + m - 1; Poly C(siz); if(siz < 64){//小于等于64项直接暴力算 for(int i = 0;i < n;i++){ for(int j = 0;j < m;j++)C[i+j] = (C[i+j] + 1LL*A[i]*B[j]%p)%p; } return C; } int fsiz = 1; while(fsiz <= siz)fsiz *= 2; for(int i = 0;i < fsiz;i++)F1[i] = F2[i] = 0; for(int i = 0;i < n;i++)F1[i] = A[i]; for(int i = 0;i < m;i++)F2[i] = B[i]; NTT(F1,fsiz,1); NTT(F2,fsiz,1); for(int i = 0;i < fsiz;i++)F1[i] = 1ll*F1[i]*F2[i]%p; NTT(F1,fsiz,-1); for(int i = 0;i < siz;i++){ C[i] = F1[i]; } return C; } const int N = 1e6+10; ll qsm(int a,int b){ int ans=1,tmp = a; while( b ){ if( b&1 ) ans = (ans * tmp)%p; tmp = (tmp * tmp)%p; b>>=1; } return ans; } int fac[N],ni_f[N]; void ini(){ fac[0]=1; int maxn = 1e6; _for(i,1,maxn) fac[i] = (fac[i-1] * i)%p; ni_f[maxn] = qsm(fac[maxn],p-2); _rep(i,maxn-1,0) ni_f[i] = ni_f[i+1] * (i+1)%p; } ll C(int n,int m){ if( m==n || m==0 ) return 1; if( n < m ) return 0; return fac[n] * ni_f[n-m]%p * ni_f[m]%p; } signed main(){ #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif IOS; ini(); int n; cin>>n; Poly f(n+1,0); _for(i,0,n){ if( n-3*i < 0 ) break; f[i] = qsm(26,n-3*i)*C(n-2*i,i)%p*fac[i]%p; } Poly g(n+1,0); _for(i,0,n){ int flag = ((n-i)&1)?-1:1; g[i] = (p + flag*ni_f[n-i])%p; } Poly h = mul(f,g); _for(i,n,2*n) cout<



