NOI模拟20220613

1好像今天的题没啥营养的样子,但是最后一个题是个好题,并且这套题对我的启发特别的多!!

开题T1,半个小时切了,但是是两个log,并且做法非常之垃圾,被吊打了

然后看T2,似乎会了,似乎又没会,卡在判断是否合法上了,考完知道用hash即可

T1 签到题

没啥营养,但是可以建树来做,每次子树加单点查,这样简单的多,比我的线段树维护单调栈又好写,跑的还快!

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<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=2e5+5;
int n,m,a[N],w[N],h[N];
int st[N][20],sta[N],top;
struct XDS{
    #define ls x<<1
    #define rs x<<1|1
    int sm[N*4],mn[N*4],mx[N*4];
    int sol(int x,int l,int r,int v){
        if(v>=mx[x])return 0;
        if(v<mn[x]||l==r)return sm[x];
        int mid=l+r>>1;
        // cerr<<x<<" "<<l<<" "<<r<<" "<<v<<" "<<mx[ls]<<" "<<sm[rs]<<endl;
        if(v>=mx[ls])return sol(rs,mid+1,r,v);
        if(v<mx[ls])return sol(ls,l,mid,v)+sm[x]-sm[ls];
        return 0;
    }
    void pushup(int x,int l,int r){
        int mid=l+r>>1;
        sm[x]=sm[ls]+sol(rs,mid+1,r,mx[ls]);
    }
    void build(int x,int l,int r){
        if(l==r){
            sm[x]=w[l];mn[x]=mx[x]=a[l];
            return ;
        }
        int mid=l+r>>1;
        build(ls,l,mid);build(rs,mid+1,r);
        mx[x]=max(mx[ls],mx[rs]);
        mn[x]=mn[ls];pushup(x,l,r);
    }
    void ins(int x,int l,int r,int ps,int v){
        if(l==r)return sm[x]+=v,void();
        int mid=l+r>>1;
        if(ps<=mid)ins(ls,l,mid,ps,v);
        else ins(rs,mid+1,r,ps,v);
        pushup(x,l,r);
    }
    int mxx,ret;
    void query(int x,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){
            ret+=sol(x,l,r,mxx);
            mxx=max(mxx,mx[x]);
            // cerr<<"query"<<" "<<x<<" "<<l<<" "<<r<<" "<<ret<<" "<<mxx<<" "<<sm[x]<<endl;
            return ;
        }
        int mid=l+r>>1;
        if(ql<=mid)query(ls,l,mid,ql,qr);
        if(qr>mid)query(rs,mid+1,r,ql,qr);
    }
    int qry(int l,int r){
        mxx=-1;ret=0;
        query(1,1,n,l,r);
        return ret;
    }
    #undef ls
    #undef rs
}xds;
bool jud(int x,int y){
    bool flag=false;
    fu(i,19,0)if(st[x][i]&&st[x][i]<=y)x=st[x][i];
    return x==y;
}
int getz(int x,int y){
    fu(i,19,0)if(st[x][i]&&(!jud(y,st[x][i])))x=st[x][i];
    if(st[x][0]==y)return st[y][0];
    return st[x][0];
}
signed main(){
    freopen("set.in","r",stdin);
    freopen("set.out","w",stdout);
    n=read();m=read();
    fo(i,1,n)a[i]=read();
    fo(i,1,n)w[i]=read();
    fo(i,1,n){
        while(top&&a[sta[top]]<a[i]){st[sta[top]][0]=i;top--;}
        sta[++top]=i;
    }
    fu(i,n,1)fo(j,1,19)st[i][j]=st[st[i][j-1]][j-1];
    xds.build(1,1,n);
    while(m--){
        int tp=read(),x=read(),y=read();
        if(tp==1){
            w[x]+=y;h[x]+=y;
            xds.ins(1,1,n,x,2*y);
        }
        else {
            if(x>y)swap(x,y);
            int z=getz(x,y),ans=0;
            if(!jud(y,z)){printf("?\n");continue;}
            if(jud(x,y))ans=xds.qry(x,z)-h[x]+h[st[z][0]];
            else ans=xds.qry(x,z)+xds.qry(y,z)-h[x]-h[y]+h[st[z][0]]-w[z];
            printf("%lld\n",ans);
        }
    }
    return 0;
}

T2 蓝超巨星

EXCRT,手推的,卡在判断上了

判断用hash,找到对应的位置之后,看每个字母的对应,然后找到对应的hash值

这里直接把每个字母的位置的hash值拿出来成上字母的权值再加起来即可

发现原串要循环我们直接在后面继续求hash,把长度变为2n,拿出长度为n的一段进行比较就行了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#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--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int N=2e5+5;
const int inf=0x3f3f3f3f3f3f3f3f;
const ull bas=131;
ull ba[N],hs[N*2],hb[30];
int n,a,b,ans=inf;char ys[30],s[N],t[N];
int ss[N],tt[N],ft[30];
int exgcd(int a,int b,int &x,int &y){
    if(!b)return x=1,y=0,a;
    int ret=exgcd(b,a%b,x,y),xx=x;
    x=y;y=xx-a/b*y;return ret;
}
int lcm(int x,int y){return x/__gcd(x,y)*y;}
int br[N],cr[N],ccr,to[N],d[N];
int ok[30];
pair<int,int> work(int a1,int b1,int a2,int b2){
    if(a1==-1)return make_pair(-1,-1);
    int x,y,g=exgcd(a2,a1,x,y);
    int bei=(b1-b2)/g;if(g*bei!=b1-b2)return make_pair(-1,-1);
    x*=bei;y*=bei;int lm=lcm(a1,a2);
    return make_pair(lm,((x*a2+b2)%lm+lm)%lm);
}
pair<int,int> get(int nm,int no,int b){
    int x,y,g=exgcd(b,nm,x,y);
    if(no%g!=0)return make_pair(-1,-1);
    x*=no/g;y*=no/g;
    int mo=nm/g,ret=(x%mo+mo)%mo;
    return make_pair(mo,ret);
}
int sol(int o){
    int nm=1,no=0,fi,se;
    fo(i,1,ccr)if(ok[i]!=-1){
        tie(nm,no)=work(nm,no,cr[i],ok[i]);
    }
    if(nm==-1)return 0;
    tie(nm,no)=get(nm,no,b);if(nm==-1)return 0;
    tie(fi,se)=get(n,o,a);if(fi==-1)return 0;
    tie(fi,se)=work(nm,no,fi,se);
    if(fi==-1)return 0;
    return se==0?fi:se;
}
signed main(){
    freopen("blue.in","r",stdin);
    freopen("blue.out","w",stdout);
    n=read();a=read();b=read();
    scanf("%s%s%s",ys+1,s+1,t+1);
    ba[0]=1;fo(i,1,n)ba[i]=ba[i-1]*bas;
    fo(i,1,n){
        ss[i]=s[i]-'a'+1;
        hs[i]=hs[i-1]*bas+ss[i];
    }
    fo(i,1,n){
        tt[i]=t[i]-'a'+1;
        if(!ft[tt[i]])ft[tt[i]]=i;
        fo(j,1,26)hb[j]*=bas;
        hb[tt[i]]+=1;
    }
    fo(i,1,26)to[i]=ys[i]-'a'+1;
    fo(i,1,26)if(!br[i]){
        br[i]=++ccr;cr[ccr]++;d[i]=cr[ccr];
        int now=to[i];
        while(!br[now]){
            br[now]=ccr;cr[ccr]++;d[now]=cr[ccr];
            now=to[now];
        }
    }
    int lm=1;fo(i,1,ccr)lm=lcm(lm,cr[i]);
    a%=n;b%=lm;
    int dc=__gcd(a,n),now=n,ct=n;
    for(int o=(n-1)/dc*dc;o>=0&&1.0*clock()/CLOCKS_PER_SEC<=0.95;o-=dc){
        while(now>o){
            now--;ct++;
            hs[ct]=hs[ct-1]*bas+ss[ct-n];
        }
        bool flag=true;ull hh=0;
        fo(i,1,ccr)ok[i]=-1;
        fo(i,1,26)if(ft[i]){
            int p=ft[i],x=((p-o-1)%n+n)%n+1;
            // cerr<<p<<endl;
            // cerr<<"SB"<<" "<<i<<endl;
            if(br[i]!=br[ss[x]]){flag=false;break;}
            int cha=(d[i]-d[ss[x]]+cr[br[ss[x]]])%cr[br[ss[x]]];
            if(ok[br[i]]==-1)ok[br[i]]=cha;
            else if(ok[br[i]]!=cha){flag=false;break;}
            hh+=hb[i]*ss[x];
        }
        // cerr<<hh<<" "<<hs[ct]-hs[ct-n]*ba[n]<<endl;
        if(hh!=hs[ct]-hs[ct-n]*ba[n])flag=false;
        if(!flag)continue;int ret=0;
        // cerr<<o<<endl;
        if(ret=sol(n-o))ans=min(ans,ret);
    }
    if(ans==inf)ans=-1;
    printf("%lld\n",ans);
    return 0;
}

T3 秘密行动

怎么也没有看出来这是个网络流题,依旧是车老师切掉了,记得联赛的时候车老师来之后讲的第一个题就是网络流的题

考完之后看了一遍题,发现确实挺像网络流的,然而我一开始以为要写高精,发现double可以存300位,于是就不用写了

建图一般,然后用指数把它变成加法即可

AC_code
#include<bits/stdc++.h>
using namespace std;
#define double long double
#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<<1)+(s<<3)+(ch^48);ch=getchar();}
    return s*t;
}
const int M=505;
const double inf=1e5;
const double eps=1e-5;
int n,m,p[15];
double fp[15],c[15][55],d[15][55],ans;
vector<pair<int,int>> vec[15];
struct NET{
    struct E{int to,nxt;double val;}e[M*4];
    int head[55],hea[55],rp,s,t;
    void init(){
        memset(head,0,sizeof(head));
        rp=1;s=n+1;t=n+2;
    }
    void add_edg(int x,int y,double z){
        e[++rp].to=y;e[rp].nxt=head[x];
        e[rp].val=z;head[x]=rp;
    }
    void add(int x,int y,double z){
        add_edg(x,y,z);add_edg(y,x,0);
    }
    int dis[55];
    bool bfs(){
        memcpy(head,hea,sizeof(hea));
        memset(dis,0x3f,sizeof(dis));
        queue<int> q;while(!q.empty())q.pop();
        q.push(s);dis[s]=0;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].nxt){
                int y=e[i].to;
                if(e[i].val<eps||dis[y]<=dis[x]+1)continue;
                dis[y]=dis[x]+1;q.push(y);
                if(y==t)return true;
            }
        }return false;
    }
    double dfs(int x,double in){
        if(x==t)return in;
        double rest=in,go=0;
        for(int i=head[x];i;head[x]=i=e[i].nxt){
            int y=e[i].to;
            if(e[i].val<eps||dis[y]!=dis[x]+1)continue;
            go=dfs(y,min(e[i].val,rest));
            if(go)rest-=go,e[i].val-=go,e[i^1].val+=go;
            else dis[y]=0;
            if(rest<eps)break;
        }return in-rest;
    }
    double dinic(){
        memcpy(hea,head,sizeof(head));
        double ret=0;
        while(bfs())ret+=dfs(s,inf);
        return ret;
    }
}net;
signed main(){
    freopen("secret.in","r",stdin);
    freopen("secret.out","w",stdout);
    n=read();m=read();
    fo(i,1,10)p[i]=read(),scanf("%Lf",&fp[i]),fp[i]=log(fp[i]);
    fo(i,1,n){
        fo(j,1,10)scanf("%Lf",&c[j][i]),c[j][i]=log(c[j][i]);
        fo(j,1,10)scanf("%Lf",&d[j][i]),d[j][i]=log(d[j][i]);
    }
    fo(i,1,m){
        int a=read(),b=read(),c=read();
        vec[c].emplace_back(a,b);
    }
    fo(i,1,10){
        net.init();
        fo(j,1,n){
            net.add(net.s,j,c[i][j]);
            net.add(j,net.t,d[i][j]);
        }
        for(pair<int,int> j:vec[i]){
            net.add_edg(j.first,j.second,fp[i]);
            net.add_edg(j.second,j.first,fp[i]);
        }
        double res=net.dinic();ans+=res;
        // cerr<<res<<endl;
    }
    ans=exp(ans);
    printf("%.10Lf",ans);
    return 0;
}
posted @ 2022-06-13 19:35  fengwu2005  阅读(97)  评论(0编辑  收藏  举报