1. 程式人生 > >8.24-8.25聯賽模擬 解題報告

8.24-8.25聯賽模擬 解題報告

bre lov sharp () 關系 floyd head mat long

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聯賽模擬 解題報告