8.24-8.25聯賽模擬 解題報告
T1:
直接模擬,然後坐標相同的點的統計用sort來去重,用map等STL會TLE。。。
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=2000050; struct data{ int x,y; }g[N]; bool cmp(const data &a,const data &b){ if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int n,flag,ans,x,y,xt,yt,cnt; int main(){ freopen("loverfinding.in","r",stdin); freopen("loverfinding.out","w",stdout); scanf("%d%d%d%d%d",&n,&x,&y,&xt,&yt); g[++cnt]=(data){x,y}; for(int i=1;i<=n;i++){ int dx,dy;scanf("%d%d",&dx,&dy); int x1=g[cnt].x+dx,y1=g[cnt].y+dy; g[++cnt]=(data){x1,y1}; if(x1==xt&&y1==yt){flag=1;break;} } if(!flag){puts("SingleDog");return 0;} sort(g+1,g+1+cnt,cmp);g[0].x=2147483647,g[0].y=2147483647; for(int i=1;i<=cnt;i++){ if(g[i].x==g[i-1].x&&g[i].y==g[i-1].y) continue; ans++; } printf("%d\n",ans); return 0; }
T2:
跟洛谷的災後重建是一樣的,都是動態加點的floyd,只不過這個題要把點和詢問sort一遍。。。
把點按照消費指數從小到大的加入圖中,然後以當前加入的點為中轉站來更新其余兩點間的距離。。。
因為中轉站是從小往大加入的,所以當前加入的中轉站k,一定是i->k,k->j路徑上的消費指數的最大值(除開起點和終點)。。。
那麽我們對於每個詢問,只把消費指數<=c的商店加入圖中,然後查詢跟一個點距離不超過d的點即可。。。
復雜度O(n^3+q*n) 或者每加入一個中轉站就把所有人的f[i]數組排序,詢問時二分,復雜度為O(n^3log+q*log)。。。
註意鄰接矩陣的Inf要>1e9,不然可能不聯通的點也被統計進了答案。。(memset(f,127/3,sizeof(f))只有40分)。。。
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #define RG register using namespace std; typedef long long ll; const int N=2000050; struct data{ int id,v; }g[N]; struct Data{ int s,c,d,id; }q[N]; int f[300][300],n,m,T,ans[N],tmp; bool cmp(const data &a,const data &b){ if(a.v==b.v) return a.id<b.id; return a.v<b.v; } bool cmp2(const Data &a,const Data &b){ return a.c<b.c; } int main(){ freopen("snackstore.in","r",stdin); freopen("snackstore.out","w",stdout); scanf("%d%d%d",&n,&m,&T); for(RG int i=1;i<=n;i++) scanf("%d",&g[i].v),g[i].id=i; //memset(f,127/3,sizeof(f)); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=1e9+1; for(RG int i=1;i<=n;i++) f[i][i]=0; for(RG int i=1;i<=m;i++){ int x,y,z;scanf("%d%d%d",&x,&y,&z); f[x][y]=min(f[x][y],z);f[y][x]=min(f[y][x],z); } for(RG int i=1;i<=T;i++) scanf("%d%d%d",&q[i].s,&q[i].c,&q[i].d),q[i].id=i; sort(g+1,g+1+n,cmp);sort(q+1,q+1+T,cmp2);int k=1; for(RG int p=1;p<=T;p++){ while(g[k].v<=q[p].c&&k<=n){ for(RG int i=1;i<=n;i++) for(RG int j=1;j<=n;j++){ f[i][j]=min(f[i][j],f[i][g[k].id]+f[g[k].id][j]); } k++; } RG int s=q[p].s,ret=0; for(RG int i=1;i<=n;i++) if(i!=s&&f[s][i]<=q[p].d) ret++; ans[q[p].id]=ret; } for(int i=1;i<=T;i++) printf("%d\n",ans[i]); return 0; }
T3:棄了。。。
T4:包含關系構成了一個DAG,那麽可以用拓撲排序或者記憶化搜索來模擬題目的意思。
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #include<queue> using namespace std; typedef long long ll; const int N=3000050; const int Mod=1e9+7; int head[N],to[N],nxt[N],cnt,v[N],du[N],n; void lnk(int x,int y){ to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt; } queue<int> Q; void topsort(){ while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=head[x];i;i=nxt[i]){ int y=to[i];(v[y]+=v[x])%=Mod;du[y]--; if(du[y]==0) Q.push(y); } } } int main(){ freopen("three_squirrels.in","r",stdin); freopen("three_squirrels.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ int k;scanf("%d",&k); for(int j=1;j<=k;j++){int y;scanf("%d",&y);lnk(y,i);du[i]++;} } v[0]=1; for(int i=0;i<=n;i++) if(!du[i]) Q.push(i); topsort();printf("%d\n",v[n]); return 0; }
T5:
首先每一步跳得盡量的大答案一定會最大,因為(a+b)^2>a^2+b^2。。。
那麽因為題目中相似子串的定義為前綴等於後綴,並且我們又要求一次跳得盡量的大,
所以每次跳躍其實就是在跳kmp的nxt數組(前綴等於後綴的最大長度)。。。所以先用kmp把nxt數組構出來。。。
然後我們要求兩個前綴的距離最大,因為每個位置i,只會跳向nxt[i],那麽這種移動關系構成了一棵樹(每個點最多一個父親)
這就是所謂的kmp樹。
那麽我們要求兩個前綴間的最長距離,就是樹的直徑。通過兩邊bfs求解。。
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> #include<queue> using namespace std; typedef long long ll; const int N=3000050; char s[N]; int len,fail[N]; int head[N],to[N],nxt[N],cnt,vis[N]; ll v[N],dis[N]; void lnk(int x,int y,ll z){ to[++cnt]=y,nxt[cnt]=head[x],v[cnt]=z,head[x]=cnt; to[++cnt]=x,nxt[cnt]=head[y],v[cnt]=z,head[y]=cnt; } void make_nxt() { int j=0; for(int i=2;i<=len;i++){ while(j&&s[j+1]!=s[i]) j=fail[j]; if(s[j+1]==s[i]) j++; fail[i]=j; } } queue<int> Q; void bfs(int x){ for(int i=0;i<=len;i++) dis[i]=0,vis[i]=0; Q.push(x);vis[x]=1; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=head[x];i;i=nxt[i]){ int y=to[i]; if(!vis[y]) dis[y]=dis[x]+v[i],vis[y]=1,Q.push(y); } } } ll sqr(ll x){return 1ll*x*x;} int main(){ freopen("savemzx.in","r",stdin); freopen("savemzx.out","w",stdout); scanf("%s",s+1);len=strlen(s+1);make_nxt(); for(int i=1;i<=len;i++) lnk(fail[i],i,sqr(1ll*i-fail[i])); bfs(0); int rt1=0;ll Max=0;for(int i=0;i<=len;i++) if(dis[i]>Max) rt1=i,Max=dis[i]; bfs(rt1); int rt2=rt1;ll ans=0;for(int i=0;i<=len;i++) if(dis[i]>ans) rt2=i,ans=dis[i]; printf("%lld\n",ans); return 0; }
T6:
萬萬沒有想到這竟然是兩道題目強行拼起來的。。。
首先這個題要維護的就是區間積,然後第一問要%p1,第二問要%phi(p2)(降冪)。。。
然後7-10個測試點都是可以用exgcd來求逆元的(肯定是互質的),所以可以直接用前綴積相除來實現。。。
前面的1-6個測試點直接用線段樹來維護區間積,註意不能%0。。。
// MADE BY QT666 #include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=3000050; int n,m,k,mod,Mod,M; ll a[N],mul[N]; ll qpow(ll x,ll y,ll mo){ll ret=1;while(y){if(y&1) (ret*=x)%=mo;(x*=x)%=mo;y>>=1;} return ret;} void exgcd(ll a,ll b,ll &x,ll &y){ if(!b) x=1,y=0; else exgcd(b,(a+b)%b,y,x),y-=x*(a/b); } void getphi(ll P){ M=P;ll res=P; for(ll i=2;i*i<=P;i++) if(res%i==0) { (M/=i)*=i-1; while(res%i==0) res/=i; } if(res>1) (M/=res)*=res-1; } int ls[N],rs[N],rt,sz; ll tr[N],tr2[N]; void pushup(int x){ tr[x]=(tr[ls[x]]*tr[rs[x]])%mod; if(Mod) tr2[x]=(tr2[ls[x]]*tr2[rs[x]])%M; } void insert(int &x,int l,int r,int id){ if(!x) x=++sz; if(l==r){tr[x]=tr2[x]=a[id];return;} int mid=(l+r)>>1; if(id<=mid) insert(ls[x],l,mid,id); else insert(rs[x],mid+1,r,id); pushup(x); } ll query1(int x,int l,int r,int xl,int xr){ if(xl<=l&&r<=xr){return tr[x];} int mid=(l+r)>>1; if(xr<=mid) return query1(ls[x],l,mid,xl,xr); else if(xl>mid) return query1(rs[x],mid+1,r,xl,xr); else return query1(ls[x],l,mid,xl,mid)*query1(rs[x],mid+1,r,mid+1,xr)%mod; } ll query2(int x,int l,int r,int xl,int xr){ if(xl<=l&&r<=xr){return tr2[x];} int mid=(l+r)>>1; if(xr<=mid) return query2(ls[x],l,mid,xl,xr); else if(xl>mid) return query2(rs[x],mid+1,r,xl,xr); else return query2(ls[x],l,mid,xl,mid)*query2(rs[x],mid+1,r,mid+1,xr)%M; } int main(){ freopen("chocolatebox.in","r",stdin); freopen("chocolatebox.out","w",stdout); scanf("%d%d%d%d%d",&n,&m,&k,&mod,&Mod);getphi(Mod); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); if(mod==1e9+7||mod==996919243){ mul[0]=1; for(int i=1;i<=n;i++) (mul[i]=mul[i-1]*a[i])%=mod; for(int i=1;i<=m;i++){ int type,l,r;scanf("%d%d%d",&type,&l,&r); ll x,y;exgcd(mul[l-1],mod,x,y);ll inv=(x+mod)%mod; ll ans=mul[r]*inv%mod;printf("%lld\n",ans); } } else if(Mod==984359||Mod==988643){ mul[0]=1; for(int i=1;i<=n;i++) (mul[i]=mul[i-1]*a[i])%=M; for(int i=1;i<=m;i++){ int type,l,r;scanf("%d%d%d",&type,&l,&r); ll x,y;exgcd(mul[l-1],M,x,y);ll inv=(x+M)%M; ll ret=mul[r]*inv%M;ll ans=qpow(k,ret,Mod);printf("%lld\n",ans); } } else if(n<=500000){ memset(tr,1,sizeof(tr));memset(tr2,1,sizeof(tr2)); for(int i=1;i<=n;i++) insert(rt,1,n,i); for(int i=1;i<=m;i++){ int type,l,r;scanf("%d%d%d",&type,&l,&r); if(type==1){ ll ret=query1(rt,1,n,l,r); printf("%lld\n",ret); } else{ ll ret=query2(rt,1,n,l,r); ll ans=qpow(k,ret,Mod);printf("%lld\n",ans); } } } return 0; }
8.24-8.25聯賽模擬 解題報告