8.24-8.25联赛模拟 解题报告
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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联赛模拟 解题报告的主要内容,如果未能解决你的问题,请参考以下文章