虽然没有炸死,
嗯第一题
(1)匹配
给定 n 个白点与 n 个黑点,分为 n 组一黑一白的点对,并要求白点一定在右下角(包括正右与正下)
求 n 组点对最小曼哈顿距离和
数据保证有合法方案
曼哈顿距离的公式: |x1−x2|+|y1−y2|
化简以后你就会发现这是一道脑筋急转弯
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#include
#include
#include
#include
#include
#include
#include
#include
#include
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自动机
但是本题支持对长字符串单个节点的修改操作
最多修改 2∗105 次
其实还是AC自动机
考虑每次查询的过程,在 Si 时我们会统计以 Si 为结尾的单词出现次数。
所以对于 Si 更改,并不会对 Si 之前节点的答案统计造成影响,只会对其后的部分字符串造成影响。
那么其后的部分字符串究竟有多长呢?
设 Sj 是 Si 所影响的最右节点,则读到 Sj 在自动机上的位置时一定与原位置不同。
考虑到最长串长度只有 100
107 级别好像很优秀
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}