Wannafly挑战赛18

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\n",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\n",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\n",ans);
    return 0;
}
posted @ 2018-06-23 00:00  RRRR_wys  阅读(1229)  评论(0编辑  收藏  举报