题意:
一张纸折叠K次,可以横着或竖着折叠,折叠后沿着十字剪开,询问剪开后剩余纸张的期望值。
题解:
横向折叠和纵向折叠对答案的影响是独立的,设横向折叠了x次,那么最后剪开完,会出现2x 条割线,即会有2x +1张纸,设纵向折叠了y次,同理,会有2y条割线,2y +1张纸,最后,纸张会被切割成 (2x + 1) * (2y +1)张,由于n = x + y,期望值可以表示为:
计算过程:
根据二项式定理,最终可转换为:
AC_CODE:
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
void solve(){
ll n;
R(n);
ll sum = powmod(2,n) + 1;
ll k1 = powmod(3,n);
ll k2 = powmod(2,n);
ll k3 = powmod(k2,mod-2);
ll k4 = k1 * k3 % mod;
k4 = k4 * 2 % mod;
sum = (sum + k4) % mod;
W(sum);
}
题意:
将n张纸铺在一起,同方向折叠k次,给定一个序列,为纸张从上到下,正反两面赋值,问展开纸张后,纸张从上到下,从左到右的值是多少?
题解:
每次折叠的过程,都是将原序列上半部分翻转并合并到下半部分的左侧,模拟即可。
AC_CODE:
void solve(){
int n,k;
R(n,k);
int p = 2 * n * powmod(2,k);
VI v;
FOR(i,1,p) {
int u;
R(u);
v.PB(u);
}
int mid = p >> 1;
int u = 1;
REPP(i,0,k) {
VI t;
VI q;
int num = 0;
int m = p >> 1;
for(auto x: v) {
num += 1;
if(num > m) break;
q.PB(x);
}
for(int ii=0,jj=m-1; ii<m; ++ii,--jj) {
v[jj] = q[ii];
}
for(int ii=0; ii<mid; ++ii) {
for(int j=ii*u; j<(ii+1)*u; ++j) {
t.PB(v[j]);
}
for(int j=(p>>1)+ii*u; j<(ii+1)*u+(p>>1); ++j) {
t.PB(v[j]);
}
}
v = t;
u <<= 1;
mid >>= 1;
}
W(v);
}