冲刺国赛模拟 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;
}
快踩