10.16考试爆炸记

虽然没有炸死,
嗯第一题
(1)匹配
给定 n 个白点与n个黑点,分为 n 组一黑一白的点对,并要求白点一定在右下角(包括正右与正下)
n组点对最小曼哈顿距离和
数据保证有合法方案

曼哈顿距离的公式: |x1x2|+|y1y2|
化简以后你就会发现这是一道脑筋急转弯

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#define int long long
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x) buf[++buf[0]]=x%10,x/=10;
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
int n,xb,yb,xw,yw;
signed main(){
    n=read();
    for(int i=1;i<=n;++i){
        xb+=read();
        yb+=read();
    }
    for(int i=1;i<=n;++i){
        xw+=read();
        yw+=read();
    }
    write(xw-xb+yb-yw);
    return 0;
}

(2)积木
有一组积木,初始状态为:
0
1 1
2 2 2
3 3 3 3
4 4 4 4 4
5 5 5 5 5 5
然后顺序被打乱了
你需要将之还原
每次只能将0块与其左上、左下、右上、右下的方块互换。
如果20步以内可行则输出答案
反之输出”too difficult”

…做过骑士精神没?

//衆以爲喜獨我哀 
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x) buf[++buf[0]]=x%10,x/=10;
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
const int final[7][7]={0,0,0,0,0,0,0,
                       0,0,0,0,0,0,0,
                       0,1,1,0,0,0,0,
                       0,2,2,2,0,0,0,
                       0,3,3,3,3,0,0,
                       0,4,4,4,4,4,0,
                       0,5,5,5,5,5,5};
const int cnk[6]={1,2,3,4,5,6};
const int movx[4]={-1,-1,1,1};
const int movy[4]={-1,0,1,0};
int T,b[7][7],sx,sy,tag,sze[6];
int check(){
    int ret=-1;
    for(int i=1;i<=6;++i)
        for(int j=1;j<=i;++j)
            if(b[i][j]!=final[i][j])
                ++ret;
    return ret;
}
bool dfs(int step,int x,int y){
    if(step>tag){
        if(check()==-1) return true;
        else return false;
    }
    if(check()+step-1>tag) return false;
    for(int i=0;i<4;++i){
        int nx=x+movx[i],ny=y+movy[i];
        if(nx>0&&nx<7&&ny>0&&ny<=nx){
            swap(b[nx][ny],b[x][y]);
            if(dfs(step+1,nx,ny)) return true;
            swap(b[nx][ny],b[x][y]);
        }
    }
    return false;
}
signed main(){
    T=read();
    while(T--){
        memset(sze,0,sizeof(sze));
        for(int i=1;i<=6;++i)
            for(int j=1;j<=i;++j){
                b[i][j]=read();
                if(b[i][j]==0){
                    sx=i;
                    sy=j;
                }
                ++sze[b[i][j]];
         }
        for(int i=0;i<=5;++i)
            if(sze[i]!=cnk[i]){
                puts("too difficult");
                continue;
            }
        for(tag=0;tag<=20;++tag)
            if(dfs(1,sx,sy)) break;
        if(tag>20) puts("too difficult");
        else{
            write(tag);
            puts("");
        }
    }
    return 0;
}

(3)字符串
emm…
SCOI2017考了一道高深的南山字符串算法
然后就有了这道字符串题
emm…
给一个字符串集T,有 n 个字符串,依次为T1,T2,...,Tn
T 中最长串为100
求在一个长字符串 S 中,T1,T2,...,Tn总共出现了多少次。

如果题面只到这里这就只是一道傻X的AC自动机

但是本题支持对长字符串单个节点的修改操作
最多修改 2105

其实还是AC自动机
考虑每次查询的过程,在 Si 时我们会统计以 Si 为结尾的单词出现次数。
所以对于 Si 更改,并不会对 Si 之前节点的答案统计造成影响,只会对其后的部分字符串造成影响。
那么其后的部分字符串究竟有多长呢?
Sj Si 所影响的最右节点,则读到 Sj 在自动机上的位置时一定与原位置不同。
考虑到最长串长度只有 100
107 级别好像很优秀

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
inline int read(){
    int i=0,f=1;
    char ch;
    for(ch=getchar();!isdigit(ch);ch=getchar())
        if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar())
        i=(i<<3)+(i<<1)+(ch^48);
    return i*f;
}
int buf[1024];
inline void write(int x){
    if(!x){putchar('0');return ;}
    if(x<0){putchar('-');x=-x;}
    while(x) buf[++buf[0]]=x%10,x/=10;
    while(buf[0]) putchar(buf[buf[0]--]+48);
    return ;
}
#define stan 111111
#define sten 111
int n,q,len1,len2,nxt[sten],ans,pos,tot,chkpos,posi;
int ansb[stan],ansa[stan],pso[stan];
char s2[sten],s1[stan],s[sten];
struct dictionary{
    int nxt[26],val,fail;
}dic[stan];
void insert(){
    len2=strlen(s2+1);
    pos=1;
    for(int i=1;i<=len2;++i){
        if(!dic[pos].nxt[s2[i]-'a'])
            dic[pos].nxt[s2[i]-'a']=++tot;
        pos=dic[pos].nxt[s2[i]-'a'];
    }
    ++dic[pos].val;
    return ;
}
void buildfail(){
    for(int i=0;i<26;++i)
        dic[0].nxt[i]=1;
    static int que[stan];
    int qe=1;que[qe]=1;
    for(int a=1;a<=qe;++a){
        int nowpos=que[a],nxtpos,failpos;
        for(int i=0;i<26;++i){
            failpos=dic[nowpos].fail;
            while(!dic[failpos].nxt[i])
                failpos=dic[failpos].fail;
            failpos=dic[failpos].nxt[i];
            nxtpos=dic[nowpos].nxt[i];
            if(nxtpos){
                dic[nxtpos].fail=failpos;
                que[++qe]=nxtpos;
            }else dic[nowpos].nxt[i]=failpos;
        }
    }
    return ;
}
signed main(){
    n=read();q=read();
    tot=1;
    for(int i=1;i<=n;++i){
        scanf("%s",s2+1);
        insert();
    }
    buildfail();
    scanf("%s",s1+1);
    len1=strlen(s1+1);
    ans=0;pso[0]=pos=1;
    for(int i=1;i<=len1;++i){
        pos=dic[pos].nxt[s1[i]-'a'];
        pso[i]=chkpos=pos;
        while(chkpos){
            ansb[i]+=dic[chkpos].val;
            chkpos=dic[chkpos].fail;
        }
        ans+=ansb[i];
    }
    write(ans);puts("");
    for(int i=1;i<=q;++i){
        posi=read();scanf("%s",s);
        s1[posi]=s[0];
        pos=pso[posi-1];
        for(int j=posi;j<=len1;++j){
            pos=dic[pos].nxt[s1[j]-'a'];
            ansa[j]=0;
            if(pos==pso[j]) break;
            chkpos=pos;
            while(chkpos){
                ansa[j]+=dic[chkpos].val;
                chkpos=dic[chkpos].fail;
            }
            ans+=(ansa[j]-ansb[j]);
            ansb[j]=ansa[j];
            pso[j]=pos;
        }
        write(ans);puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值