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;
}
QQ:2953174821