冲刺国赛模拟 38

我球球你们不要到处转发我博客点踩了。这玩意已经超过yspm峰值了,这就是钓鱼的动力吗。还没踩过的赶紧去踩一下。然而 yspm 的强大之处在于每天都能保证 5-20 个踩不等,不得不说非常厉害。

二次整数规划在写了,估计今天晚上能写完。求求你们不要让我写树上邻域数点。我是不是学 yspm 把踩隐藏了可以减少一部分的踩数。

智力游戏

确实挺智力的。NOI 前最后一场模拟赛考普及 bfs。

#include <iostream>
#include <algorithm>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
using namespace std;
typedef unsigned long long ull;
const ull prm=131;
int mx;
struct node{
    int p;
    char od;
    int x;
};
map<ull,int>mp;
struct gra{
    int s[10][10];
    vector<node>ans;
    ull hs(){
        ull hs=0;
        for(int i=1;i<=6;i++)for(int j=1;j<=6;j++)hs=hs*prm+(s[i][j]+'0');
        return hs;
    }
}tmp;
queue<gra>q;
gra bfs(){
    int hs=0;
    q.push(tmp);mp[tmp.hs()]=1;
    while(!q.empty()){
        gra u=q.front();q.pop();
        if(u.s[3][5]==1&&u.s[3][6]==1)return u;
        for(int x=1;x<=mx;x++){
            int x1=7,y1=7,x2=0,y2=0;
            for(int i=1;i<=6;i++){
                for(int j=1;j<=6;j++){
                    if(u.s[i][j]==x){
                        x1=min(x1,i);y1=min(y1,j);x2=max(x2,i);y2=max(y2,j);
                    }
                }
            }
            if(x1==x2){
                tmp=u;
                int dy=y1,ddy=y2;
                for(int d=1;d<=6;d++){
                    dy--;
                    if(tmp.s[x1][dy]!=0)break;
                    tmp.s[x1][dy]=x;tmp.s[x1][ddy]=0;
                    ddy--;
                    ull hs=tmp.hs();
                    if(mp.find(hs)!=mp.end())continue;
                    mp[hs]=1;
                    tmp.ans.push_back({x,'L',d});
                    q.push(tmp);
                    tmp.ans.pop_back();
                }
                tmp=u;
                dy=y2,ddy=y1;
                for(int d=1;d<=6;d++){
                    dy++;
                    if(tmp.s[x1][dy]!=0)break;
                    tmp.s[x1][dy]=x;tmp.s[x1][ddy]=0;
                    ddy++;
                    ull hs=tmp.hs();
                    if(mp.find(hs)!=mp.end())continue;
                    mp[hs]=1;
                    tmp.ans.push_back({x,'R',d});
                    q.push(tmp);
                    tmp.ans.pop_back();
                }
            }
            else{
                tmp=u;
                int dx=x1,ddx=x2;
                for(int d=1;d<=6;d++){
                    dx--;
                    if(tmp.s[dx][y1]!=0)break;
                    tmp.s[dx][y1]=x;tmp.s[ddx][y1]=0;
                    ddx--;
                    ull hs=tmp.hs();
                    if(mp.find(hs)!=mp.end())continue;
                    mp[hs]=1;
                    tmp.ans.push_back({x,'U',d});
                    q.push(tmp);
                    tmp.ans.pop_back();
                }
                tmp=u;
                dx=x2,ddx=x1;
                for(int d=1;d<=6;d++){
                    dx++;
                    if(tmp.s[dx][y1]!=0)break;
                    tmp.s[dx][y1]=x;tmp.s[ddx][y1]=0;
                    ddx++;
                    ull hs=tmp.hs();
                    if(mp.find(hs)!=mp.end())continue;
                    mp[hs]=1;
                    tmp.ans.push_back({x,'D',d});
                    q.push(tmp);
                    tmp.ans.pop_back();
                }
            }
        }
    }
    return tmp;
}
int main(){
    memset(tmp.s,-1,sizeof(tmp.s));
    for(int i=1;i<=6;i++){
        for(int j=1;j<=6;j++){
            scanf("%d",&tmp.s[i][j]);
            mx=max(mx,tmp.s[i][j]);
        }
    }
    vector<node>ans=bfs().ans;
    printf("%d\n",(int)ans.size());
    for(node x:ans)printf("%d %c %d\n",x.p,x.od,x.x);
    return 0;
}

区域划分

挺智慧的。

能够猜到的结论是只要没有相同元素相邻且三种元素都出现就有解,否则无解。证明题解说可以归纳,这结论我确实是猜的,然而并不会构造于是冲了一发区间 dp。

考虑构造。用 \(0\) 划分出所有段,即 \(012121212012121212\cdots\) 这样的东西。对于相邻的两端,若一个 \(1\) 一个 \(2\) 那直接连起来没问题。现在 \(0\) 左右都是一个数,假设是 \(1\)。那么对于所有的 \(0\),把它和前面第一个 \(2\) 连起来,并把后边第一个 \(1\) 和这个 \(2\) 也连起来就可以把这样的段合并起来。现在只有一个段了,随便连一下就好了。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
int n,a[100010],cnt[3],pre[100010],nxt[100010];
void del(int x){
    pre[nxt[x]]=pre[x];
    nxt[pre[x]]=nxt[x];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),pre[i]=i-1,nxt[i]=i+1;
    pre[1]=n,nxt[n]=1;
    for(int i=1;i<=n;i++){
        if(a[i]==a[nxt[i]]){
            puts("No");return 0;
        }
        cnt[a[i]]++;
    }
    if(!cnt[0]||!cnt[1]||!cnt[2]){
        puts("No");return 0;
    }
    puts("Yes");
    for(int i=1;i<=n;i++){
        if(a[i]==0){
            if(a[pre[i]]+a[nxt[i]]==3&&--cnt[0]){
                printf("%d %d\n",pre[i],nxt[i]);del(i);
            }
        }
    }
    for(int i=1;i<=n;i=nxt[i]){
        if(a[i]==0&&a[nxt[i]]+a[nxt[nxt[i]]]==3){
            for(int j=nxt[nxt[nxt[i]]];j!=i;j=nxt[j]){
                if(a[j]==0){
                    printf("%d %d\n",pre[pre[j]],j);
                    printf("%d %d\n",pre[pre[j]],nxt[j]);
                    del(pre[j]);del(j);
                }
            }
            for(int j=nxt[nxt[i]];nxt[j]!=i;j=nxt[j]){
                printf("%d %d\n",i,j);
            }
            return 0;
        }
    }
    return 0;
}

基因识别

冲个带修莫队冲过 6e5,我不好说是数据水了还是卡不满。

在 SA 上二分出每个串对应的区间,跑带修莫队即可,复杂度 \(O(n^{\frac 53})\),然而可以跑过,我也很震撼。甚至题解都是这个东西。

更好的做法是根号分治,但是我不会。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#define int long long
using namespace std;
int n,tot,m,sq,a[600010];
char s[600010],t[600010];
int sa[600010],rk[600010],cnt[600010],rk2[600010],id[600010],key[600010];
void getsa(){
    int m=127;
    for(int i=1;i<=n;i++){
        rk[i]=s[i];cnt[rk[i]]++;
    }
    for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
    for(int i=n;i>=1;i--)sa[cnt[rk[i]]--]=i;
    for(int w=1;;w<<=1){
        int p=0;
        for(int i=n;i>n-w;i--)id[++p]=i;
        for(int i=1;i<=n;i++)if(sa[i]>w)id[++p]=sa[i]-w;
        for(int i=1;i<=m;i++)cnt[i]=0;
        for(int i=1;i<=n;i++)key[i]=rk[id[i]],cnt[key[i]]++;
        for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
        for(int i=n;i>=1;i--)sa[cnt[key[i]]--]=id[i];
        for(int i=1;i<=n;i++)rk2[i]=rk[i];
        p=0;
        for(int i=1;i<=n;i++){
            if(rk2[sa[i]]==rk2[sa[i-1]]&&rk2[sa[i]+w]==rk2[sa[i-1]+w])rk[sa[i]]=p;
            else rk[sa[i]]=++p;
        }
        if(p==n){
            for(int i=1;i<=n;i++)sa[rk[i]]=i;break;
        }
        m=p;
    }
}
int val[600010],belong[600010];
int check(char t[],int pos){
    int len=strlen(t+1);
    for(int i=1;i<=len;i++){
        if(s[pos+i-1]>t[i])return 1;
        if(s[pos+i-1]<t[i])return -1;
    }
    return 0;
}
int getl(char t[]){
    int l=0,r=n+1;
    while(l<r){
        int mid=(l+r)>>1;
        if(check(t,sa[mid])>=0)r=mid;
        else l=mid+1;
    }
    return l;
}
int getr(char t[]){
    int l=0,r=n+1;
    while(l<r){
        int mid=(l+r+1)>>1;
        if(check(t,sa[mid])>0)r=mid-1;
        else l=mid;
    }
    return l;
}
bool JUD;
struct ques{
    int l,r,t,id;
	bool operator<(const ques& s)const{
        if(!JUD){
            if(l/sq!=s.l/sq)return l<s.l;
            return r<s.r;
        }
        else{
            if(l/sq!=s.l/sq)return l<s.l;
            if(r/sq!=s.r/sq)return r<s.r;
            return t<s.t;
        }
	}
}q[600010];
struct node{
    int x,val;
}upd[600010];
int sum,num[600010],ans[600010];
void add(int x){
    if(!num[x])sum+=val[x];
    num[x]++;
}
void del(int x){
    num[x]--;
    if(!num[x])sum-=val[x];
}
void update(int t){
    if(num[upd[t].x])sum+=upd[t].val;
    val[upd[t].x]+=upd[t].val;
}
void modify(int t){
    if(num[upd[t].x])sum-=upd[t].val;
    val[upd[t].x]-=upd[t].val;
}
signed main(){
    scanf("%lld%lld",&tot,&m);
    for(int i=1;i<=tot;i++){
        scanf("%lld%s",&val[i],t+1);
        int len=strlen(t+1);
        for(int j=1;j<=len;j++)s[++n]=t[j],belong[n]=i;
        s[++n]='z'+1;
    }
    getsa();
    for(int i=1;i<=n;i++)a[i]=belong[sa[i]];
    int T=0,cnt=0;
    for(int i=1;i<=m;i++){
        int od;scanf("%lld",&od);
        if(od==1){
            scanf("%s",t+1);
            int l=getl(t),r=getr(t);cnt++;
            q[cnt]={l,r,T,cnt};
        }
        else{
            int x,y;scanf("%lld%lld",&x,&y);
            T++;upd[T]={x,y};
        }
    }
    if(!T){
        sq=pow(n,0.5);
    }
    else{
        sq=pow(n,2.0/3);JUD=true;
    }
    sort(q+1,q+cnt+1);
    for(int i=1,l=1,r=0,t=0;i<=cnt;i++){
		while(l>q[i].l)add(a[--l]);
		while(r<q[i].r)add(a[++r]);
		while(l<q[i].l)del(a[l++]);
		while(r>q[i].r)del(a[r--]);
		while(t<q[i].t)update(++t);
		while(t>q[i].t)modify(t--);
		ans[q[i].id]=sum;
	}
	for(int i=1;i<=cnt;i++)printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2023-07-18 15:23  gtm1514  阅读(113)  评论(0编辑  收藏  举报