Wannafly挑战赛18
A. 序列
先考虑暴力,相邻两个树之间乘上给定的三种数,递推出下一个位置填什么,然后再check一下,最后一位是否为1即可。这样时间显然不行,但是给我们一种思路,就是中间的转换关系,确定唯一一个序列。现在的目标是让最后一位出现1,可以如果不管1,由-2和0.5取凑出1需要两个-2和两个0.5。那所有的转换中,就只要保证有若干组(-2,-2,0.5,0.5)存在,其他地方为1即可。具体公式见代码
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
#define mem(W) memset(W,0,sizeof(W))
typedef long long ll;
inline int read() {
char c=getchar();int x=0,f=1;
while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
using namespace std;
double a[1111];
int n;
const int mod = 1e9 + 7;
ll ans,c[1111][1111];
ll C(int n,int m){
return c[n][m];
}
int main() {
scanf("%d",&n);
rep(i,0,n)c[i][0]=c[i][i]=1;
rep(i,1,n)rep(j,1,i){
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
rep(i,0,(n-1)/4){
ans = (ans + (C(n-1,i*4)*C(4*i,2*i))%mod)%mod;
}
printf("%lld
",ans);
return 0;
}
B. 随机数
设(P_n)是前n次出现奇数次的概率,单次出现1的概率(X = frac{a}{10000}), 那么有
[P_n=(1-X)P_{n-1}+X(1-P_{n-1})=(1-2X)P_{n-1}+X, P_0=0
]
由中学数学可知,通项为:(P_n=frac{1-(1-2X)^n}{2})
之后发现n很大,所以我胆子很大的用java写了快速幂......单次运算复杂度太高TLE,实际上碰见这种指数项远大于模数的情况第一个就该想到循环节,对于mod为素数(mod-1)就是循环节,然后就可以把n降低,直接套公式即可。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
#define mem(W) memset(W,0,sizeof(W))
typedef long long ll;
inline int read() {
char c=getchar();int x=0,f=1;
while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
using namespace std;
ll n,a;
const int mod = 1e9 + 7;
ll q_pow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
char s[1000100];
int main() {
scanf(" %lld %s",&a,s);
int len=strlen(s);
rep(i,0,len-1)n=(n*10+s[i]-'0')%(mod-1);
ll X = (a*q_pow(10000LL,mod-2))%mod;
ll ans = (1-q_pow(1-2*X,n)+mod)%mod*q_pow(2,mod-2)%mod;
ans=(ans+mod)%mod;
printf("%lld
",ans);
return 0;
}
C. 异或和
思考如何快速求出一个位置的期望,曼哈顿距离常见套路,把x,y拆开考虑,那么把x,y都投影到坐标轴上,分别预处理每个位置左右两边的1到它的距离和,o(n)预处理,然后枚举一下就解决了。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define frep(i,a,b) for(int i=a;i>=b;--i)
#define pb push_back
#define mem(W) memset(W,0,sizeof(W))
typedef long long ll;
inline int read() {
char c=getchar();int x=0,f=1;
while(!isdigit(c)){if(f=='-')f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
using namespace std;
const int N = 2000+50;
int n,m;
const int mod = 1e9 + 7;
ll q_pow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
char s[2002];
ll num,X[N],Y[N],LX[N],RX[N],LY[N],RY[N];
int main() {
scanf("%d%d",&n,&m);
rep(i,1,n){
scanf(" %s",s+1);
rep(j,1,m)if(s[j]=='1'){
++X[i];
++Y[j];
++num;
}
}
int t=X[1];
rep(i,2,n){
LX[i] = (LX[i-1] + t)%mod;
t=(t+X[i])%mod;
}
t=Y[1];
rep(i,2,m){
LY[i]=(LY[i-1]+t)%mod;
t=(t+Y[i])%mod;
}
t=X[n];
frep(i,n-1,1){
RX[i] = (RX[i+1] + t)%mod;
t=(t+X[i])%mod;
}
t=Y[m];
frep(i,m-1,1){
RY[i] = RY[i+1] + t;
t=(t+Y[i])%mod;
}
ll ans=0;
rep(i,1,n)rep(j,1,m){
ll tmp = (((RX[i]+LX[i]+RY[j]+LY[j])%mod*q_pow(num,mod-2))%mod)%mod;
ans^=tmp;
}
printf("%lld
",ans);
return 0;
}