noip模拟73[被卡常了]

noip模拟73 solutions

可惜了我的300分,一向号称代码常数小的我,被卡没了.....呜呜呜

没关系,以后考试没事就卡卡常,想睡觉的时候就卡卡常

不过今天被骂了,因为机房是我家,我觉得我一点都不懈怠

我就.....算了,不计较了

说实话吧我也不是故意的,想不出题来就想喝水,一看杯子里没有,不就接水去了嘛\(QAQ\)

然后吧喝完水还想喝,然后就不停地上厕所

好吧以后应该避免这样的事,毕竟真正考试的时候我不能接水

上厕所还要候着,考试还那么难,还是好好养成习惯吧,加油!!!

T1 小L的疑惑

这就大水题一个直接前缀和搞一搞就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e5+5;
int n,a[N],sum;
signed main(){
    #ifdef oj
        freopen("math.in","r",stdin);
        freopen("math.out","w",stdout);
    #endif
    scanf("%lld",&n);
    fo(i,1,n)scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    fo(i,1,n){
        if(a[i]>sum+1)break;
        sum+=a[i];
    }
    printf("%lld",sum+1);
}

T2 小L的数列

这个就是我被卡常卡到和暴力一个分的!!!!

气死了真的,但是后来卡过去了

直接矩阵快速幂维护指数就好了,最后统计答案。。。

AC_code
%: pragma GCC optimize(12)
#include<bits/stdc++.h>
using namespace std;
#define oj
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=205;
const int mod=998244353;
int n,m,b[N],f[N];
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=1ll*ret*x%mod;
        x=1ll*x*x%mod;y>>=1;
    }return ret;
}
struct matrix{
    int x[N][N];
    matrix(){memset(x,0,sizeof(x));}
    matrix operator * (matrix a)const{
        matrix ret;
        fo(i,1,m)fo(k,1,m){
            if(!x[i][k])continue;
            fo(j,1,m){
                ret.x[i][j]=(ret.x[i][j]+1ll*x[i][k]*a.x[k][j])%(mod-1);
            }
        }
        return ret;
    }
}xs,ma,ans;
matrix mksm(matrix x,int y){
    matrix ret;
    fo(i,1,m)ret.x[i][i]=1;
    while(y){
        if(y&1)ret=ret*x;
        x=x*x;y>>=1;
    }return ret;
}
signed main(){
    #ifdef oj
        freopen("seq.in","r",stdin);
        freopen("seq.out","w",stdout);
    #endif
    scanf("%d%d",&n,&m);
    fo(i,1,m)scanf("%d",&b[i]);
    fo(i,1,m)scanf("%d",&f[i]);
    fo(i,1,m)xs.x[i][1]=b[i];
    fo(i,1,m-1)xs.x[i][i+1]=1;
    fo(i,1,m)ma.x[1][i]=f[m+1-i];
    if(n<=m){
        printf("%d",f[n]);
        return 0;
    }
    xs=mksm(xs,n-m);
    fo(i,1,1)fo(j,1,1){
        ans.x[i][j]=1;
        fo(k,1,m){
            ans.x[i][j]=1ll*ans.x[i][j]*ksm(ma.x[i][k],xs.x[k][j])%mod;
        }
    }
    printf("%d",ans.x[1][1]);
}

T3 连边

这个题也好水,但是我考场上脑袋瓜子坏掉了

每一个白点要么最短路经过一条边连着一个白点,要么直接连着一个黑点

所以我们先找一个最短路,然后取所有最短路中第一条边最小的就是答案了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e5+5;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,m,bw[N],ans;
int dis[N],an[N];
int to[N<<2],nxt[N<<2],val[N<<2],head[N],rp;
void add_edg(int x,int y,int z){
    to[++rp]=y;
    val[rp]=z;
    nxt[rp]=head[x];
    head[x]=rp;
}
bool vis[N];
queue<int> q;
signed main(){
    #ifdef oj
        freopen("minimum.in","r",stdin);
        freopen("minimum.out","w",stdout);
    #endif
    scanf("%lld%lld",&n,&m);
    memset(dis,0x3f,sizeof(dis));
    fo(i,1,n){
        scanf("%lld",&bw[i]);
        if(bw[i])q.push(i),dis[i]=0,vis[i]=true;
    }
    fo(i,1,m){
        int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);
        add_edg(x,y,z);add_edg(y,x,z);
    }
    while(!q.empty()){
        int x=q.front();q.pop();vis[x]=false;
        for(int i=head[x];i;i=nxt[i]){
            int y=to[i];
            if(dis[y]<dis[x]+val[i])continue;
            if(dis[y]>dis[x]+val[i])an[y]=val[i];
            dis[y]=dis[x]+val[i];
            if(an[y]>val[i])an[y]=val[i];
            if(!vis[y])q.push(y),vis[y]=true;
        }
    }
    fo(i,1,n)if(!bw[i])ans+=an[i];
    if(ans)printf("%lld",ans);
    else printf("impossible");
}

T4 小L的有向图

这个状压\(DP\),我考场上竟然想到了

可是我傻不拉几的给我的复杂度加了一个\(n\)

\(TLE\)了,后来就直接切掉了

\(f_s\)表示,处理完\(s\)这个集合,最终得到的方案数

我们每次只需要枚举下一个点加啥

因为是拓扑序,所以所有有边指向当前点的点都必须在\(s\)集合内

所以我们只需要找到所有边中起点在\(s\)集合内,终点是当前点的个数,这些边是可选可不选的,有\(2^cnt\)种可能

AC_code
%: pragma GCC optimize(12)
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=23;
const int M=25*25;
const int mod=998244353;
int n,m;
int edg[N][N],fr[N];
int f[1<<23],cnt[1<<23];
signed main(){
    #ifdef oj
        freopen("topology.in","r",stdin);
        freopen("topology.out","w",stdout);
    #endif
    scanf("%lld%lld",&n,&m);
    fo(i,1,m){
        int x,y;scanf("%lld%lld",&x,&y);
        edg[x][y]=true;
        fr[y]|=(1<<x-1);
    }
    int U=(1<<n)-1;f[0]=1;
    fo(s,0,U){
        fo(i,1,n)if((s>>i-1)&1)cnt[s]++;
    }
    fo(s,0,U){
        fo(i,1,n){
            if((s>>i-1)&1)continue;
            int tot=cnt[s&fr[i]];
            f[s|(1<<i-1)]=(f[s|(1<<i-1)]+f[s]*(1ll<<tot))%mod;
        }
    }
    printf("%lld",f[U]);
}

T5 group

插头\(DP\)我不会

T6 ZZH与计数

这题我直接跳了

T7 中国象棋

这个好秒啊,我直接去看题解了,真的想不到

\(f_{i,j,k}\)表示,我转移到了第\(i\)行,当前有\(j\)列有\(1\)个数,有\(k\)列有\(2\)个数

这样每次直接枚举转移系数直接转移就好了,只要定义出来了就非常好做了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fxt(i,x,y) for(int i=(x);i<=(y);i++)
#define pyt(i,x,y) for(int i=(x);i>=(y);i--)
const int N=105;
const int mod=9999973;
int n,m,ans;
int f[N][N][N];
signed main(){
    freopen("chess.in","r",stdin);
    freopen("chess.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    f[0][0][0]=1;
    fxt(i,0,n-1){
        fxt(j,0,m){
            fxt(k,0,m-j){
                if(!f[i][j][k])continue;
                f[i+1][j][k]=(f[i+1][j][k]+f[i][j][k])%mod;
                if(j>=1)f[i+1][j-1][k+1]=(f[i+1][j-1][k+1]+f[i][j][k]*j)%mod;
                if(j>=2)f[i+1][j-2][k+2]=(f[i+1][j-2][k+2]+f[i][j][k]*j*(j-1)/2)%mod;
                if(j+1+k<=m)f[i+1][j+1][k]=(f[i+1][j+1][k]+f[i][j][k]*(m-j-k))%mod;
                if(j+2+k<=m)f[i+1][j+2][k]=(f[i+1][j+2][k]+f[i][j][k]*(m-j-k)*(m-j-k-1)/2)%mod;
                if(j+1+k<=m&&j>=1)f[i+1][j][k+1]=(f[i+1][j][k+1]+f[i][j][k]*(m-j-k)*j)%mod;
            }
        }
    }
    fxt(i,0,m)fxt(j,0,m-i)ans=(ans+f[n][i][j])%mod;
    printf("%lld",ans);
}

T8 奇妙的 Fibonacci

这个好像有一个结论,是我颓题解颓到的

\(f_j|f_i=j|i\)

这样就好做了,我们只需要找到一个数的约数个数和,约数平方和

这些都可以用线性筛搞定

直接看代码吧,这个我根本就口述不了

代码中\(mn_i\)表示\(i\)中最小的质因子出现的次数

\(el_i\)表示\(i\)中把最小质因子全部除掉之后的结果

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fxt(i,x,y) for(int i=(x);i<=(y);i++)
#define pyt(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e7+5;
const int mod=1e9+7;
int n,q,a,b,c;
int pi[N],cnt,ct[N],sm[N],mn[N],el[N];
int ans1,ans2;
bool vis[N];
signed main(){
    scanf("%lld",&n);
    scanf("%lld%lld%lld%lld",&q,&a,&b,&c);
    ct[1]=sm[1]=1;
    fxt(i,2,c){
        if(!vis[i]){
            pi[++cnt]=i;
            ct[i]=2;
            sm[i]=(i*i+1)%mod;
            mn[i]=el[i]=1;
        }
        for(int j=1;j<=cnt&&pi[j]*i<=c;j++){
            vis[i*pi[j]]=true;
            if(i%pi[j]==0){
                mn[i*pi[j]]=mn[i]+1;
                el[i*pi[j]]=el[i];
                ct[i*pi[j]]=(ct[i]/(mn[i*pi[j]]))*(mn[i*pi[j]]+1);
                sm[i*pi[j]]=(sm[i]*pi[j]%mod*pi[j]+sm[el[i]])%mod;
                break;
            }
            mn[i*pi[j]]=1;
            el[i*pi[j]]=i;
            ct[i*pi[j]]=ct[i]<<1;
            sm[i*pi[j]]=(sm[i]+sm[i]*pi[j]%mod*pi[j])%mod;
        }
    }
    fxt(i,1,n){
        ans1=(ans1+ct[q]+(q&1))%mod;
        ans2=(ans2+sm[q]+(q&1)*4)%mod;
        q=(q*a+b)%c+1;
    }
    printf("%lld\n%lld",ans1,ans2);
}
posted @ 2021-10-10 21:15  fengwu2005  阅读(49)  评论(0编辑  收藏  举报