noip模拟64[开题失误]

noip模拟64 solutions

这个吧,AaMuXiiiiii太强了,把第一题切了,我非常生气,然后给了他一巴掌

然后几秒种后我也切了(注意不是考场上)

不过我竟然对最后一题有感觉,不知道是做题策略的问题,还是我脑子抽抽了

所以以后还是好好看题,好好的决定开题顺序。。。

T1 三元组

这个我也是枚举\(b^2\)的位置,但是我是\(n^2\)的,直接枚举的好吧

但是我也想仔细观察观察但是没观察出来

a的值域是连续的

这样的话我们只需要找到\(a\)的值域的左右端点,直接在\(c^3\)的树状数组上查就好了

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 T,n,m,ans;
struct BIT{
    int tr[N];
    void ins(int x,int v){
        if(x==0)return tr[0]+=v,void();
        for(int i=x;i<m;i+=(i&(-i)))tr[i]+=v;
    }
    int query(int x){
        if(x<0)return 0;
        int ret=tr[0];
        for(int i=x;i>0;i-=(i&(-i)))ret+=tr[i];
        return ret;
    }
}bit;
signed main(){
    #ifdef oj
        freopen("exclaim.in","r",stdin);
        freopen("exclaim.out","w",stdout);
    #endif
    scanf("%lld",&T);
    fo(t,1,T){
        ans=0;
        scanf("%lld%lld",&n,&m);
        fo(i,1,n)bit.ins(i*i*i%m,1);
        fo(i,1,n){
            int now=i*i%m;
            int l=(1+i*i)%m,r=(i+i*i)%m;
            if(i%m==0)ans+=bit.query(m-1)*(i/m);
            else if(l<=r)ans+=bit.query(r)-bit.query(l-1)+bit.query(m-1)*(i/m);
            else ans+=(bit.query(m-1)-bit.query(l-1))+bit.query(r)+bit.query(m-1)*(i/m);
            bit.ins(i*i*i%m,-1);
        }
        printf("Case %lld: %lld\n",t,ans);
    }
}

T2 简单的字符串

这个别找我,我是暴力艹过去的

直接\(n^3\)开干,用两个\(hash\),一个用来判断字符集是否相等

这个实现的话,就直接在对应的字母的那一位\(+1\)就好了

另一个用来判断字符串是否相等就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define ull unsigned 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=5005;
const ull bas=13331;
int n,a[N],ji[N],ans;
ull ba[N],hs[N],gs[N];
ull ksm(ull x,int y){
    ull ret=1;
    while(y){
        if(y&1)ret=ret*x;
        x=x*x;y>>=1;
    }return ret;
}
signed main(){
    #ifdef oj
        freopen("s.in","r",stdin);
        freopen("s.out","w",stdout);
    #endif
    scanf("%d",&n);
    fo(i,1,n)scanf("%d",&a[i]);
    ba[0]=1;fo(i,1,n)ba[i]=ba[i-1]*bas;
    fo(i,1,n)hs[i]=hs[i-1]*bas+a[i];
    fo(i,1,n)gs[i]=gs[i-1]+ksm(bas,a[i]);
    for(int l=2;l<=n;l+=2){
        fo(i,1,n-l+1){
            int j=i+l-1,len=l>>1;
            if(gs[j]-gs[i+len-1]!=gs[i+len-1]-gs[i-1])continue;
            bool flag=false;
            fo(k,0,len-1)if(hs[i+k]-hs[i-1]*ba[k+1]==hs[j]-hs[j-k-1]*ba[k+1]&&hs[i+len-1]-hs[i+k]*ba[len-1-k]==hs[j-k-1]-hs[i+len-1]*ba[len-1-k]){flag=true;break;}
            if(flag)ans++;
        }
    }
    printf("%d",ans);
}

正解戳这里

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=105;
int n,m,mod,ans;
char s[N];
struct matrix{
    int x[N][N];
    matrix(){memset(x,0,sizeof(x));}
    matrix operator * (matrix a)const{
        matrix ret;
        fo(i,1,n)fo(j,1,n)fo(k,1,n)ret.x[i][j]=(ret.x[i][j]+x[i][k]*a.x[k][j])%mod;
        return ret;
    }
}xs;
signed main(){
    #ifdef oj
        freopen("tour.in","r",stdin);
        freopen("tour.out","w",stdout);
    #endif
    scanf("%lld",&n);
    fo(i,1,n){
        scanf("%s",s+1);
        fo(j,1,n)if(s[j]=='Y')xs.x[i][j]=1;
    }
    scanf("%lld%lld",&m,&mod);
    matrix res;m--;
    fo(i,1,n)res.x[i][i]=1;
    fo(t,1,m){
        res=res*xs;
        fo(i,1,n)ans=(ans+res.x[i][i])%mod;
    }
    
    printf("%lld",ans);
}

另外一个就比较高级了,可以给\(i\)\(i+n\)连边再给\(i+n\)\(i+n\)连边

这样你每次统计的答案就全部放到\(i+n\)上去了

然后就可以直接快速幂了

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=205;
int n,m,mod,ans;
char s[N];
struct matrix{
    int x[N][N];
    matrix(){memset(x,0,sizeof(x));}
    matrix operator * (matrix a)const{
        matrix ret;
        fo(i,1,2*n)fo(j,1,2*n)fo(k,1,2*n)ret.x[i][j]=(ret.x[i][j]+x[i][k]*a.x[k][j])%mod;
        return ret;
    }
}xs;
signed main(){
    #ifdef oj
        freopen("tour.in","r",stdin);
        freopen("tour.out","w",stdout);
    #endif
    scanf("%lld",&n);
    fo(i,1,n){
        scanf("%s",s+1);
        fo(j,1,n)if(s[j]=='Y')xs.x[i][j]=1;
        xs.x[i][n+i]=1;xs.x[n+i][n+i]=1;
    }
    scanf("%lld%lld",&m,&mod);
    matrix res;
    fo(i,1,2*n)res.x[i][i]=1;
    while(m){
        if(m&1)res=res*xs;
        xs=xs*xs;m>>=1;
    }
    fo(i,1,n)ans=(ans+res.x[i][n+i])%mod;
    printf("%lld",ans-n);
}

最后一个正解就是分治的算法,因为后面的矩阵可以直接由前面的举证相乘得到

所以这样就可以直接优化到\(log\)

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=105;
int n,m,mod,ans;
char s[N];
struct matrix{
    int x[N][N];
    matrix(){memset(x,0,sizeof(x));}
    matrix operator * (matrix a)const{
        matrix ret;
        fo(i,1,n)fo(j,1,n)fo(k,1,n)ret.x[i][j]=(ret.x[i][j]+x[i][k]*a.x[k][j])%mod;
        return ret;
    }
    matrix operator + (matrix a)const{
        matrix ret;
        fo(i,1,n)fo(j,1,n)ret.x[i][j]=(x[i][j]+a.x[i][j])%mod;
        return ret;
    }
}xs,ys;
void print(matrix a){
    fo(i,1,n){fo(j,1,n)cout<<a.x[i][j]<<" ";cout<<endl;}
    cout<<endl;
}
matrix sol(int l,int r){
    if(l==r)return xs;
    int mid=l+r-1>>1;
    matrix le=sol(l,mid);
    if(l+mid+mid==r){
        matrix ri=le*ys;
        ys=ys*ys*xs;
        matrix ret=le+ri+ys;
        return ret;
    }
    else {
        matrix ri=le*ys;
        ys=ys*ys;
        matrix ret=le+ri;
        return ret;
    }
}
signed main(){
    #ifdef oj
        freopen("tour.in","r",stdin);
        freopen("tour.out","w",stdout);
    #endif
    scanf("%lld",&n);
    fo(i,1,n){
        scanf("%s",s+1);
        fo(j,1,n)if(s[j]=='Y')xs.x[i][j]=1;
    }ys=xs;
    scanf("%lld%lld",&m,&mod);m--;
    matrix res=sol(1,m);
    fo(i,1,n)ans=(ans+res.x[i][i])%mod;
    printf("%lld",ans);
}

T4 过河

这个首先需要一个神猪,这个存在于所有的打架关系

我们必须找到这样一个神猪,这样才可以吧他们都运过去

第一步我们就把神猪运过去,

然后慢慢的把剩下的猪运过去,注意要保证这些猪不能构成打架关系

但是这一次运的最后一只是可以的,因为你人去看这这些猪了

然后下一步就是将神猪运回来,再把剩下的运过去,这时候第一次运的猪可以和其他的有交集

但是剩下的就不行了,因为你将神猪运回去的时候,你只能保证这个时候他们不打架

所以我们要做的工作就是去掉两只猪,让剩下的没有交集

也就是将每一只猪连接,去掉两只猪的话,可以构成一个二分图

可以直接枚举这两个点来判断

正解是,枚举其中一个点,便利一遍整个图,看可不可以删掉另外一个点使得构成二分图

这样的话这个点必须在所有的奇数环上,直接判断就好了

并且这个点不能同时被一个奇环和一个偶环跨越

跨越的意思是指去掉端点的跨越

至于为什么,因为一个奇环和一个偶环可以构成一个新的奇环

但是这个奇环和偶环必须一端在父亲那边,另一端在同一颗子树内

如果不在同一颗子树内,就不能构成新的奇环

所以维护奇环偶环的标记时,可以将这个标记标在儿子身上,这样就可以有效避免不在同一颗子树内的情况

AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define mm(x) memset(x,0,sizeof(x))
#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=1005;
const int M=3005;
int T,n,m;
struct node{
    int a,b,c;
    node(){}
    bool operator < (node x){
        if(a==x.a&&b==x.b)return c<x.c;
        if(a==x.a)return b<x.b;
        return a<x.a;
    }
    bool operator == (node x){
        return a==x.a&&b==x.b&&c==x.c;
    }
}sca[M];
int ain,sum[N];
int to[M*2],nxt[M*2],head[N],rp;
void add_edg(int x,int y){
    to[++rp]=y;
    nxt[rp]=head[x];
    head[x]=rp;
}
int son[N],dep[N],fa[N];
bool cat[N],vie[M*2],via[N],can[N];
int odd[N],cir;
int evo[N],eve[N];//down for one
void dfs(int x,int f,int d){
    dep[x]=d;fa[x]=f;via[x]=true;can[x]=true;
    for(int i=head[x];i;i=nxt[i]){
        if(vie[i])continue;
        vie[i]=vie[i^1]=true;
        int y=to[i];
        if(cat[y])continue;
        if(via[y]){
            int tmp=dep[x]-dep[y]+1;
            if(tmp&1)odd[x]++,odd[fa[y]]--,cir++;
            if(tmp&1)evo[x]++,evo[son[y]]--;
            else eve[x]++,eve[son[y]]--;
            continue;
        }
        son[x]=y;dfs(y,x,d+1);
        if(eve[y]&&evo[y])can[x]=false;
        eve[x]+=eve[y],evo[x]+=evo[y],odd[x]+=odd[y];
    }
}
signed main(){
    #ifdef oj 
        freopen("river.in","r",stdin);
        freopen("river.out","w",stdout);
    #endif
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        memset(sum,0,sizeof(sum));
        fo(i,1,m)scanf("%d%d%d",&sca[i].a,&sca[i].b,&sca[i].c);
        sort(sca+1,sca+m+1);m=unique(sca+1,sca+m+1)-sca-1;
        fo(i,1,m)sum[sca[i].a]++,sum[sca[i].b]++,sum[sca[i].c]++;
        int flag=0;fo(i,1,n)if(sum[i]==m)flag++,ain=i;
        if(!flag){printf("no\n");continue;}
        if(flag>1){printf("sbyes\n");continue;}
        flag=0;rp=1;mm(head);mm(cat);
        fo(i,1,m){
            if(sca[i].a==ain)add_edg(sca[i].b,sca[i].c),add_edg(sca[i].c,sca[i].b);
            if(sca[i].b==ain)add_edg(sca[i].a,sca[i].c),add_edg(sca[i].c,sca[i].a);
            if(sca[i].c==ain)add_edg(sca[i].b,sca[i].a),add_edg(sca[i].a,sca[i].b);
        }
        fo(i,1,n){
            cat[i]=true;
            mm(via);mm(vie);mm(can);
            mm(odd);mm(eve);mm(evo);cir=0;
            fo(k,1,n)if(!cat[k]&&!via[k])dfs(k,0,1);
            fo(k,1,n){
                if(k==i||!can[k])continue;
                if(odd[k]==cir){printf("yes\n");goto sb;}
            }
            cat[i]=false;
        }
        printf("no\n");sb:;
    }
}
posted @ 2021-10-01 19:46  fengwu2005  阅读(74)  评论(0编辑  收藏  举报