省选模拟1

今天考试考的非常烂,不想多说......

考场上啥也没有想出来,只是零零散散的一点性质

需要集中精力,也可能需要拓宽思维,因为我思维的面有点过于狭窄了...

没啥了,没啥,就挺自卑的,挺难受的,感觉啥也不是

仅是第一场吧,后面会好起来!!

T1 ARC100F

很难,但不是很妙

分情况,讨论...

不说,但是这里写下一种\(DP\),可以在\(\mathcal{O(n)}\)时间内得到长度为\(n\)的彩虹序列有多少个

\[f_i=f_{i-1}*k+k!*(k^{i-k}-f_{i-k}) \]

每一个彩虹序列都由第一个排列出现的位置计算

前一半就是第一个排列出现的位置在\(i-k\)之前

后一半就是第一个排列出现的位置是\(i-k+1\),这样可以保证不重不漏

AC_code
#include<bits/stdc++.h>
using namespace std;
#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--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
const int mod=1e9+7;
const int N=25005;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,m,k,a[N],ll,rr;
int pos[N],sum,ans;
int f[N][405],g[N][405],sf[N][405],sg[N][405];
int jc[N],inv[N];
void spj2(){
    f[0][min(ll,k-1)]=1;fo(i,0,min(ll,k-1))sf[0][i]=1;
    fo(i,1,n-m){
        fo(j,1,k-1)f[i][j]=(f[i-1][j-1]*(k-j+1)+sf[i-1][j])%mod;
        fu(j,k-1,1)sf[i][j]=(sf[i][j+1]+f[i][j])%mod;
    }
    g[0][min(rr,k-1)]=1;fo(i,0,min(rr,k-1))sg[0][i]=1;
    fo(i,1,n-m){
        fo(j,1,k-1)g[i][j]=(g[i-1][j-1]*(k-j+1)+sg[i-1][j])%mod;
        fu(j,k-1,1)sg[i][j]=(sg[i][j+1]+g[i][j])%mod;
    }
    fo(i,0,n-m)ans=(ans-sf[i][1]*sg[n-m-i][1]%mod+mod)%mod;
    printf("%lld",ans);
}
void spj3(){
    f[0][0]=sf[0][0]=1;
    fo(i,1,n){
        fo(j,1,k-1){
            f[i][j]=(f[i-1][j-1]*(k-j+1)+sf[i-1][j])%mod;
            g[i][j]=(g[i-1][j-1]*(k-j+1)+sg[i-1][j])%mod;
            if(j>=m)g[i][j]=(g[i][j]+f[i][j])%mod;
        }
        fu(j,k-1,1){
            sf[i][j]=(sf[i][j+1]+f[i][j])%mod;
            sg[i][j]=(sg[i][j+1]+g[i][j])%mod;
        }
    }
    fo(i,1,k-1)ans=(ans-g[n][i]*inv[k]%mod*jc[k-m]%mod+mod)%mod;
    printf("%lld",ans);
}
signed main(){
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    n=read();k=read();m=read();
    fo(i,1,m)a[i]=read();
    bool fl1=false,fl2=false;
    fo(i,1,min(m,k-1)){
        if(!pos[a[i]])sum++;
        else fl2=true;
        pos[a[i]]=i;
    }
    jc[0]=1;fo(i,1,k)jc[i]=jc[i-1]*i%mod;
    inv[0]=1;inv[k]=ksm(jc[k],mod-2);
    fu(i,k-1,1)inv[i]=inv[i+1]*(i+1)%mod;
    fo(i,k,m){
        if(pos[a[i]]<=i-k)sum++;
        else fl2=true;
        pos[a[i]]=i;
        if(sum==k){fl1=true;break;}
        if(pos[a[i-k+1]]==i-k+1)sum--;
    }
    ans=(n-m+1)*ksm(k,n-m)%mod;
    if(fl1){printf("%lld",ans);return 0;}
    fo(i,1,m)pos[a[i]]=0;
    fo(i,1,m){
        if(pos[a[i]]){ll=i-1;break;}
        pos[a[i]]=i;
    }
    fo(i,1,m)pos[a[i]]=0;
    fu(i,m,1){
        if(pos[a[i]]){rr=m-i;break;}
        pos[a[i]]=i;
    }
    if(fl2){spj2();return 0;}
    spj3();
    return 0;
}

T2 CF1361E

这个不难,就是有点不在我的思考范围内

首先可以很快找到一个有趣点,考虑如何判断其他点

其他点的子树内一定一共有且仅有一条返祖边,并且返祖边☞的父亲一定是一个有趣点

\(set\)启发式合并就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
random_device you;
mt19937 pyt(you());
int rd(int l,int r){
    uniform_int_distribution<> ee(l,r);
    return ee(pyt);
}
const int N=1e5+5;
int tt,T,n,m,an[N],ans,sum;
struct E{int to,nxt;}e[N*2];
int head[N],rp,dep[N],cnt;bool flag,vis[N],pd[N];
void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;}
void dfs(int x,int d){
    if(dep[x])return ;
    dep[x]=d;vis[x]=true;cnt++;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(!dep[y])dfs(y,d+1);
        else if(vis[y])continue;
        else if(dep[y])flag=false;
    }
    vis[x]=false;
}
bool jud(int x){
    // cerr<<x<<" ";
    fo(i,1,n)vis[i]=dep[i]=0;cnt=0;
    flag=true;dfs(x,1);
    fo(i,1,n)vis[i]=dep[i]=0;
    if(flag&&cnt==n)return true;
    else return false;
}
vector<int> vec[N];
multiset<int> st[N];
int sz[N];
void dfs_fi(int x,int d){
    if(dep[x])return ;
    dep[x]=d;vis[x]=true;cnt++;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(!dep[y]){
            dfs_fi(y,d+1);
            if(st[x].size()<st[y].size())swap(st[x],st[y]);
            for(int i:st[y])st[x].insert(i);
        }
        else if(vis[y]){
            st[x].insert(y);
        }
        else if(dep[y])flag=false;
    }
    vis[x]=false;
    if(st[x].find(x)!=st[x].end())st[x].erase(x);
    if(st[x].size()==1)vec[*st[x].begin()].push_back(x);
}
void dfs_ans(int x){
    vis[x]=true;
    if(pd[x]){
        for(int i:vec[x])pd[i]=true;
        if(x!=an[1])an[++ans]=x;
    }
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(vis[y])continue;
        dfs_ans(y);
    }
}
signed main(){
    freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    T=read();tt=T;
    for(tt=1;tt<=T;tt++){
        fo(i,1,n)head[i]=0;rp=0;
        n=read();m=read();
        fo(i,1,m){
            int x=read(),y=read();
            add_edg(x,y);
        }ans=0;
        fo(i,1,1000){
            int x=rd(1,n);
            if(jud(x)){an[ans=1]=x;break;}
        }
        pd[an[1]]=true;
        dfs_fi(an[1],1);dfs_ans(an[1]);
        sort(an+1,an+ans+1);
        fo(i,1,ans)printf("%d ",an[i]);
        printf("\n");
        fo(i,1,n)vis[i]=pd[i]=false,dep[i]=0,sz[i]=0,vec[i].clear(),st[i].clear();
    }
    return 0;
}

T3 CF1290F

很难,很妙

这里不在赘述题解,只是写一下通过这道题对数位\(dp\)的进一步理解

一般来说都是从高位到低位\(dp\),这样我们设置两个状态,是否卡上/下界

这个可以变化一下,变成从低位到高位\(dp\),那么我们原来的两个状态就要变成,是否大于上界/小于下界

这样我们可以通过高位的变化来调整这个东西

那么如果加上高低位之间是有影响的,我们知道进位比退位好写

于是我们一般采用低位到高位的写法,这个题就是这样

还有一个更加重要的东西

一般我们拆位的时候仅仅拆一个变量

而这个题,我们两个变量都要拆位,然后容易懵逼

发现两个拆位之间是有关系的,于是我们可以一起做,看贡献就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
const int mod=998244353;
const double pi=acos(-1.0);
const int M=505;
int n,m,ans;
int f[32][23][23][23][23][2][2];
struct XL{int x,y;}xl[6];
int ck(int x,int y,int z){
    if(x^y)return x<y?1:0;
    return z;
}
int dfs(int d,int zx,int fx,int zy,int fy,int dx,int dy){
    if(d==30)return (!zx&&!fx&&!zy&&!fy&&!dx&&!dy);
    if(~f[d][zx][fx][zy][fy][dx][dy])return f[d][zx][fx][zy][fy][dx][dy];
    int &ret=f[d][zx][fx][zy][fy][dx][dy],now=(m>>d)&1;ret=0;
    fo(s,0,(1<<n)-1){
        int x=0,y=0;
        fo(i,1,n)if((s>>i-1)&1){
            if(xl[i].x>=0)fx+=xl[i].x;
            else zx-=xl[i].x;
            if(xl[i].y>=0)fy+=xl[i].y;
            else zy-=xl[i].y;
        }
        if((zx&1)==(fx&1)&&(zy&1)==(fy&1)){
            ret=(ret+dfs(d+1,zx>>1,fx>>1,zy>>1,fy>>1,ck(now,zx&1,dx),ck(now,zy&1,dy)))%mod;
        }
        fo(i,1,n)if((s>>i-1)&1){
            if(xl[i].x>=0)fx-=xl[i].x;
            else zx+=xl[i].x;
            if(xl[i].y>=0)fy-=xl[i].y;
            else zy+=xl[i].y;
        }
    }
    return ret;
}
signed main(){
    freopen("shape.in","r",stdin);
    freopen("shape.out","w",stdout);
    n=read();m=read();memset(f,-1,sizeof(f));
    fo(i,1,n)xl[i].x=read(),xl[i].y=read();
    printf("%d",(dfs(0,0,0,0,0,0,0)-1+mod)%mod);
}
posted @ 2022-01-11 18:34  fengwu2005  阅读(121)  评论(2编辑  收藏  举报