7.27 随 (rand)+单(single)+题(problem)

T1 随 (rand)

dp+矩阵优化+原根

看着题解懵了一晚上加一上午,最后还是看了DeepinC的博客才把暴力码出来,正解看得一知半解,循环矩阵也不太明白,先留坑吧。暴力里用二维矩阵快速幂会tle成20,跟打特判没啥区别。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MOD 1000000007
using namespace std;
ll n,m,mod,a[100100],down,anns,v[100100],f[100100][1001],base[1001][1001],ans[1001],c[1001][1001];
ll quick(ll x,ll p,ll md)
{
    ll as=1;
    while(p){
        if(p&1) as=as*x%md;
        x=x*x%md;
        p>>=1;
    }
    return as;
}
ll mul_x()
{
    for(int i=0;i<mod;i++){
        for(int j=0;j<mod;j++){
            for(int k=0;k<mod;k++){
                c[i][j]=(c[i][j]+base[i][k]*base[k][j]%MOD)%MOD;
            }
        }
    }
    for(int i=0;i<mod;i++){
        for(int j=0;j<mod;j++){
            base[i][j]=c[i][j];
            c[i][j]=0;
        }
    }
}
ll mul_ans()
{
    for(int i=0;i<mod;i++){
        for(int j=0;j<mod;j++){
            c[0][j]=(c[0][j]+ans[i]*base[i][j]%MOD)%MOD;
        }
    }
    for(int i=0;i<mod;i++){
        ans[i]=c[0][i];
        c[0][i]=0;
    }
}
void quickpow(ll p)
{
    ans[1]=1;
    while(p){
        if(p&1) mul_ans();
        mul_x();
        p>>=1;
    }
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&mod);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    if(mod==2){
        puts("1");
        return 0;
    }
    if(n==1){
        anns=quick(a[1],m,mod);
        printf("%lld",anns);
        return 0;
    }
    down=quick(n,MOD-2,MOD);
    for(int i=0;i<mod;i++){
        for(int j=1;j<=n;j++){
            (base[i][i*a[j]%mod]+=down)%=MOD;
        }
    }
    quickpow(m);
    for(int i=0;i<mod;i++)
        anns=(anns+i*ans[i])%MOD;
    printf("%lld\n",anns);
}
暴力50
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MOD 1000000007
using namespace std;
ll n,m,mod,a[100100],down,anns,v[100100],f[100100][1001],base[1001],ans[1001],c[1001],qpow[1001],al[1001],rt;
ll quick(ll x,ll p,ll md)
{
    ll as=1;
    while(p){
        if(p&1) as=as*x%md;
        x=x*x%md;
        p>>=1;
    }
    return as;
}
ll mul_x()
{
    for(int i=0;i<mod;i++){
        for(int j=0;j<mod;j++){
            c[j]=(c[j]+base[i]*base[(j-i+mod)%mod]%MOD)%MOD;
        }
    }
    for(int i=0;i<mod;i++){
        base[i]=c[i];
        c[i]=0;
    }
}
ll mul_ans()
{
    for(int i=0;i<mod;i++){
        for(int j=0;j<mod;j++){
            c[j]=(c[j]+ans[i]*base[(j-i+mod)%mod]%MOD)%MOD;
        }
    }
    for(int i=0;i<mod;i++){
        ans[i]=c[i];
        c[i]=0;
    }
}
void quickpow(ll p)
{
    ans[0]=1;
    while(p){
        if(p&1) mul_ans();
        mul_x();
        p>>=1;
    }
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&mod);
    for(int i=1;i<=mod;i++) al[i]=-1;
    for(int i=1;i<mod;i++){
        ll now=1,j;
        for(j=0;j<=mod-2;j++){
            if(al[now]==-1){
                al[now]=j;
                qpow[j]=now;
                now=now*i%mod;
            }
            else break;
        }
        if(j==mod-1){
            rt=i;
            break;
        }
        else for(int k=1;k<mod;k++) al[k]=-1;
    }
    mod--;
    down=quick(n,MOD-2,MOD);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]=al[a[i]],(base[a[i]]+=down)%=MOD;
    quickpow(m);
    for(int i=0;i<mod;i++)
        anns=(anns+qpow[i]*ans[i])%MOD;
    printf("%lld\n",anns);
}
懵逼AC

T2 单(single)树形dp+一堆乱七八糟的式子(主要是我自己推不出来)

问题一:dfs一遍维护出每个节点的儿子的权值和sum[ ](包括自己),同时暴力求解b[1](我们认为1为根),即每个节点的sum[ ]值之和。显然sum[1]=Σa[i]。

然后我们就可以发现b[y]=sum[1]-sum[y]+b[x]-sum[y]=b[x]+sum[1]-sum[y]*2 (y为x的儿子)一遍dfs就可以得到所有节点的b[ ]值,问题得解。

问题二:对于上面的式子进行移项 b[y]-b[x]=sum[1]-sum[y]*2 手玩一下多写几项

                b[yy]-b[y]=sum[1]-sum[yy]*2

                b[yyy]-b[yy]-sum[1]-sum[yyy]*2

根据高考数学中学习数列的经验(什么玩意)我们发现把所有式子求和就可以消掉一些项  b[yyy]-b[x]=(n-1)*sum[1]-sum[y]*2-sum[yy]*2-sum[yyy]*2

现在看起来好像还是没法算,但别忘了b[x]=sum[y]+sum[yy]+sum[yyy],所以把上面那个式子加上2*b[x],右边那一坨就可以消没了。设c[y]=b[y]-b[x],cnt=Σc[i];

所以cnt+2*b[1]=(n-1)*sum[1],(1就是总根)sum[1]得解,再带回上面的式子,sum[i]得解,a[x]=sum[x]-Σsum[y](y为x的儿子)dfs一遍a[ ]就求出来了。

考试的时候不知道想什么呢,dp都没看出来,直接求两点之间距离暴力求解,第二问高斯消元,还消炸了,double和int的转换变成shi,压根没往这块想。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
struct node
{
    ll to,nxt;
}t[400100];
ll T,n,tot,tpy,nxt[400100],a[100100],b[100100],sum[100100],Sum,c[100100],cnt;
bool vis[100100];
void init()
{
    tot=0;
    memset(nxt,0,sizeof(nxt));
}
void add(ll x,ll y)
{
    t[++tot].to=y;
    t[tot].nxt=nxt[x];
    nxt[x]=tot;
}
void dfs(ll x)
{
    sum[x]=a[x];
    for(ll i=nxt[x];i;i=t[i].nxt){
        ll y=t[i].to;
        if(vis[y]) continue;
        vis[y]=1;
        dfs(y);
        sum[x]+=sum[y];
        b[1]+=sum[y];//cout<<y<<" "<<sum[y]<<" "<<b[1]<<endl;
    }
}
void Dfs(ll x)
{
    for(ll i=nxt[x];i;i=t[i].nxt){
        ll y=t[i].to;//cout<<y<<endl;
        if(vis[y]) continue;
        b[y]=b[x]+Sum-2*sum[y];
        vis[y]=1;
        Dfs(y);
    }
}
void worka()
{
    memset(b,0,sizeof(b));
    memset(sum,0,sizeof(sum));
    Sum=0;
    for(ll i=1;i<=n;i++) scanf("%lld",&a[i]),Sum+=a[i];
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    dfs(1);
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    Dfs(1);
    for(ll i=1;i<=n;i++)
        printf("%lld ",b[i]);
    puts("");
}
void DFs(ll x)
{
    for(ll i=nxt[x];i;i=t[i].nxt){
        ll y=t[i].to;
        if(vis[y]) continue;
        vis[y]=1;
        c[y]=b[y]-b[x];
        cnt+=c[y];
        DFs(y);
    }
}
void DFS(ll x)
{
    for(ll i=nxt[x];i;i=t[i].nxt){
        ll y=t[i].to;
        if(vis[y]) continue;
        vis[y]=1;
        a[x]-=a[y];
        DFS(y);
    }
}
void workb()
{
    memset(a,0,sizeof(a));cnt=0;
    for(ll i=1;i<=n;i++) scanf("%lld",&b[i]);
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    DFs(1);
    a[1]=(cnt+b[1]*2)/(n-1);
    for(ll i=2;i<=n;i++) a[i]=(a[1]-c[i])/2;
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    DFS(1);
    for(ll i=1;i<=n;i++) printf("%lld ",a[i]);
    puts("");
}
int main()
{
    scanf("%lld",&T);
    while(T--){
        init();
        scanf("%lld",&n);
        ll u,v;
        for(ll i=1;i<n;i++){
            scanf("%lld%lld",&u,&v);
            add(u,v);add(v,u);
        }
        scanf("%lld",&tpy);
        if(tpy==0) worka();
        if(tpy==1) workb();
    }
}
single

T3 题(problem)模拟7 T2visit原题稍改,很可惜,考场上列的式子样例死活过不去,就打了个暴力dp转移,水了几个点。

tpy==0:ans=C(n,i)*C(i,i/2)*C(n-i,(n-i)/2) 从n步中拿出i步左右走,其中i/2步向有走,剩下n-i步中(n-i)/2步向下走。

tpy==1:卡特兰数

tpy==2:设f[i]为走了i步回到(0,0)的方案数,设上一次走了j步回到(0,0),f[i]=f[i-j]*Cat(j/2-1)*4  /*为啥-1我也不知道,*4是因为这j步可以在4个方向上走*/

tpy==3:tpy1+tpy2 ans=C(n,i)*Cat(i/2)*Cat((n-i)/2)   n步中选出i步左右走,走的情况就是卡特兰数。

考试时间留的太少,居然没看出来是卡特兰数,悲伤。

#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
#define mod 1000000007
using namespace std;
ll n,tpy,tot,prime[100100],ans,inv[100100],fac[100100],facinv[100100],f[100100];
bool mark[100100];
void init()
{
    fac[0]=1;inv[1]=1;facinv[0]=1;
    for(int i=1;i<=n+1;i++){
        if(i!=1) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
        fac[i]=fac[i-1]*i%mod;
        facinv[i]=facinv[i-1]*inv[i]%mod;
    }
}
ll C(ll a,ll b)
{
    return fac[a]*facinv[b]%mod*facinv[a-b]%mod;
}
void work0()
{
    init();ans=0;
    for(int i=0;i<=n;i+=2)
        ans=(ans+C(n,i)*C(i,i>>1)%mod*C(n-i,(n-i)>>1)%mod)%mod;
    printf("%lld\n",ans);
}
void work1()
{
    init();ans=1;
    ans=C(n,n>>1)*inv[(n>>1)+1]%mod;
    printf("%lld\n",ans);
}
void work2()
{
    init();f[0]=1;
    for(int i=2;i<=n;i+=2)
        for(int j=0;j<=i;j+=2)
            f[i]=(f[i]+f[i-j]*C(j-2,(j>>1)-1)%mod*inv[j>>1]%mod*4%mod)%mod;
    printf("%lld\n",f[n]);
}
void work3()
{
    init();ans=0;
    for(int i=0;i<=n;i+=2)
        ans=(ans+C(n,i)*C(i,i>>1)%mod*inv[(i>>1)+1]%mod*C(n-i,(n-i)>>1)%mod*inv[((n-i)>>1)+1]%mod)%mod;
    printf("%lld\n",ans);
}
int main()
{
    scanf("%lld%lld",&n,&tpy);
    if(tpy==0) work0();
    if(tpy==1) work1();
    if(tpy==2) work2();
    if(tpy==3) work3(); 
}
problem

%%%liu_runda

猜你喜欢

转载自www.cnblogs.com/jrf123/p/11258038.html