2018 Multi-University Training Contest 7
1001 Age of Moyu (HDU 6386)
思路:
把Dijkstra的vis数组改成set判一判就好了....
//By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=800050; int n,m,xx,yy,zz,first[N],nxt[N],v[N],w[N],tot,dis[N]; set<int>vis[N]; void add(int x,int y,int z){w[tot]=z,v[tot]=y,nxt[tot]=first[x],first[x]=tot++;} struct Node{int now,weight,from;}jy; bool operator<(Node a,Node b){return a.weight>b.weight;} priority_queue<Node>pq; void Dijkstra(){ memset(dis,0x3f,sizeof(dis));dis[1]=0; jy.now=1,jy.weight=0,jy.from=-1; pq.push(jy); while(!pq.empty()){ Node t=pq.top();pq.pop(); if(vis[t.now].find(t.from)!=vis[t.now].end())continue; vis[t.now].insert(t.from); for(int i=first[t.now];~i;i=nxt[i]){ int W=(w[i]!=t.from); if(vis[v[i]].find(w[i])==vis[v[i]].end()&&dis[v[i]]>=t.weight+W){ dis[v[i]]=t.weight+W; jy.now=v[i],jy.weight=dis[v[i]];jy.from=w[i]; pq.push(jy); } } } } int main(){ while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;i++)first[i]=-1;tot=0; for(int i=1;i<=n;i++)vis[i].clear(); for(int i=1;i<=m;i++){ scanf("%d%d%d",&xx,&yy,&zz); add(xx,yy,zz),add(yy,xx,zz); }Dijkstra(); printf("%d\n",dis[n]>n?-1:dis[n]); } }
1005 GuGuFishtion (HDU 6390)
定义了一个函数 $G_u(a,b)=$$\frac{\varphi(ab)}{\varphi(a)\varphi(b)}$
让你求$\Sigma_{a=1}^{m}\Sigma_{b=1}^{n}G_u(a,b) (mod\ p)$
我们可以推一发公式
$G_u(a,b)=\frac{\varphi(ab)}{\varphi(a)\varphi(b)}$
设:
$\varphi(a)=\Pi\ (p_i-1)*P_i\ ^{a_1}$
$\varphi(b)=\Pi\ (p_i-1)*P_i\ ^{a_2}$
则:
$\varphi(ab)=\Pi\ (p_i-1)*p_i^{a_1+a_2-1}$
$\varphi(a)*\varphi(b)=\Pi\ (p_i-1)^2*p^{a_1+a_2-2}$
$\frac{\varphi(ab)}{\varphi(a)\varphi(b)}=\Pi\ \frac{p_i}{p_i-1}$
我们发现还是很难搞...
把式子变一变形
$\frac{\varphi(ab)}{\varphi(a)\varphi(b)}=\Pi\ \frac{p_i}{p_i-1}=\Pi \frac{p_i^{a_i}}{(p_i-1)^{a_i-1}}=\frac{gcd(a,b)}{\varphi (gcd(a,b))}$
神奇的事情发生了233333
再把式子变个形
$\Sigma_{a=1}^m\Sigma_{b=1}^n\frac{gcd(a,b)}{\varphi (gcd(a,b))}$
$=\Sigma_{a=1}^m\Sigma_{b=1}^n\Sigma_{k=1}^{min(n,m)}[k==gcd(a,b)]\frac{k}{\varphi(k)}$
把k提到前面
$=\Sigma_{k=1}^{min(n,m)}\frac{k}{\varphi(k)}\Sigma_{a=1}^m\Sigma_{b=1}^n[k==gcd(a,b)]$
这就好做多了
可以用mobius反演,容斥也可以
BZOJ 2005
//By SiriusRen #include <bits/stdc++.h> using namespace std; #define int long long const int N=1000050; int phi[N],prime[N],tot,vis[N],cases,m,n,p,inv[N],f[N]; void init(){ phi[1]=prime[1]=1; for(int i=2;i<N;i++){ if(!vis[i])phi[i]=i-1,prime[++tot]=i; for(int j=1;j<=tot&&i*prime[j]<N;j++){ vis[i*prime[j]]=1,phi[i*prime[j]]=phi[i]*(prime[j]-1); if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;} } } } signed main(){ scanf("%lld",&cases),init(); while(cases--){ scanf("%lld%lld%lld",&m,&n,&p); if(n>m)swap(n,m); inv[1]=1; for(int i=2;i<=n;i++)inv[i]=(p-p/i)*inv[p%i]%p; int ans=0; for(int i=n;i;i--){ f[i]=(n/i)*(m/i); for(int j=2;i*j<=n;j++)f[i]-=f[i*j]; ans=(ans+f[i]%p*inv[phi[i]]%p*i)%p; }printf("%lld\n",ans); } }
1008 Traffic Network in Numazu (HDU 6393)
调到自闭++
我用的线段树
//By SiriusRen #include <bits/stdc++.h> using namespace std; #define int long long const int N=200050; int cases,n,q,op,xx,yy,zz,first[N],nxt[N],v[N],w[N],tot,stk[N],top; int incircle[N],revinc[N],cnt,vis[N],tim,in[N],out[N],wei[N],T,rec[N],deep[N]; int fa[N][20],tmpwei[N],recwei[N],cirwei,tmpid[N],recid[N],revrecid[N],cngwei[N]; void add(int x,int y,int z){w[tot]=z,v[tot]=y,nxt[tot]=first[x],first[x]=tot++;} void dfs(int x){ stk[++top]=x;vis[x]=1; for(int i=first[x];~i;i=nxt[i])if(v[i]!=stk[top-1]){ tmpwei[top]=w[i],tmpid[top]=i/2+1; if(!vis[v[i]])dfs(v[i]); else if(!incircle[v[i]]){ for(int j=top;j;j--){ incircle[stk[j]]=++cnt,revinc[cnt]=stk[j]; recwei[cnt]=tmpwei[j];cirwei+=recwei[cnt]; recid[cnt]=tmpid[j],revrecid[tmpid[j]]=cnt; if(stk[j]==v[i])break; } } } top--; } struct Segtree{ int tree[N<<3]; void build(int l,int r,int pos){ tree[pos]=0; if(l==r)return; int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; build(l,mid,lson),build(mid+1,r,rson); } void insert(int l,int r,int pos,int num,int wei){ if(l==r){tree[pos]=wei;return;} int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; if(mid<num)insert(mid+1,r,rson,num,wei); else insert(l,mid,lson,num,wei); tree[pos]=tree[lson]+tree[rson]; } int query(int l,int r,int pos,int L,int R){ if(l>=L&&r<=R)return tree[pos]; int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1; if(mid<L)return query(mid+1,r,rson,L,R); else if(mid>=R)return query(l,mid,lson,L,R); else return query(l,mid,lson,L,R)+query(mid+1,r,rson,L,R); } }seg[2]; void dfs2(int x,int F,int dep){ deep[x]=dep; in[x]=++tim;fa[x][0]=F;if(x!=revinc[T])rec[x]=revinc[T]; seg[1].insert(1,n*2,1,tim,wei[x]); for(int i=first[x];~i;i=nxt[i])if(v[i]!=F&&!incircle[v[i]]){ cngwei[i/2+1]=v[i];wei[v[i]]=w[i],dfs2(v[i],x,dep+1); }out[x]=++tim; seg[1].insert(1,n*2,1,tim,-wei[x]); } int lca(int x,int y){ if(deep[y]>deep[x])swap(x,y); for(int i=19;~i;i--) if(deep[fa[x][i]]>=deep[y])x=fa[x][i]; if(x==y)return x; for(int i=19;~i;i--) if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } signed main(){ scanf("%lld",&cases); while(cases--){ scanf("%lld%lld",&n,&q); for(int i=1;i<=n*2;i++)first[i]=-1,vis[i]=incircle[i]=wei[i]=cngwei[i]=rec[i]=0; cnt=tot=tim=cirwei=0; for(int i=1;i<=n;i++){ scanf("%lld%lld%lld",&xx,&yy,&zz); add(xx,yy,zz),add(yy,xx,zz); } dfs(1),seg[0].build(1,cnt,1),seg[1].build(1,n*2,1); for(int i=1;i<=cnt;i++)seg[0].insert(1,cnt,1,i,recwei[i]); for(T=1;T<=cnt;T++)dfs2(revinc[T],0,1); for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; for(int i=1;i<=q;i++){ scanf("%lld%lld%lld",&op,&xx,&yy); if(!op){ if(cngwei[xx]){ seg[1].insert(1,n*2,1,in[cngwei[xx]],yy); seg[1].insert(1,n*2,1,out[cngwei[xx]],-yy); } else{ seg[0].insert(1,cnt,1,revrecid[xx],yy); cirwei=cirwei-recwei[revrecid[xx]]+yy; recwei[revrecid[xx]]=yy; } } else{ if(xx==yy){puts("0");continue;} if(rec[xx]==rec[yy]&&rec[xx]){ int t=seg[1].query(1,n*2,1,1,in[xx])+seg[1].query(1,n*2,1,1,in[yy]); printf("%lld\n",t-2*seg[1].query(1,n*2,1,1,in[lca(xx,yy)])); } else if(rec[xx]!=rec[yy]){ int t=0; if(rec[xx])t+=seg[1].query(1,n*2,1,1,in[xx]),xx=rec[xx]; if(rec[yy])t+=seg[1].query(1,n*2,1,1,in[yy]),yy=rec[yy]; int l=incircle[xx],r=incircle[yy]; if(l==r)goto ed; if(l>r)swap(l,r);l++; t+=min(seg[0].query(1,cnt,1,l,r),cirwei-seg[0].query(1,cnt,1,l,r)); ed:printf("%lld\n",t); } else{ int l=incircle[xx],r=incircle[yy],rem=0; if(l==r)goto ed2; if(l>r)swap(l,r);l++; rem=min(seg[0].query(1,cnt,1,l,r),cirwei-seg[0].query(1,cnt,1,l,r)); ed2:printf("%lld\n",rem); } } } } }
1009 Tree (HDU 6394)
(可以用树分块做
LCT做法和BZOJ 2002差不多
x和fa^a[x]连边
改a[x]的时候cnt掉原来的边,倍增找到新点,link上
询问的时候,把x所在的点makeroot一下,查询size即可。
//By SiriusRen #pragma GCC optimize("O3") #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=200050; int fa[N],ch[N][2],rev[N],size[N],n,op,q[N],top,a[N],m,xx,yy,F[N][20]; bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} void push_up(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+1;} void push_down(int x){if(rev[x])rev[ch[x][0]]^=1,rev[ch[x][1]]^=1,rev[x]=0,swap(ch[x][0],ch[x][1]);} void rotate(int p){ int q=fa[p],y=fa[q],x=(ch[q][1]==p); ch[q][x]=ch[p][!x],fa[ch[q][x]]=q; ch[p][!x]=q,fa[p]=y; if(!isroot(q)){ if(ch[y][0]==q)ch[y][0]=p; if(ch[y][1]==q)ch[y][1]=p; }fa[q]=p,push_up(q); } void splay(int x){ q[++top]=x; for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i]; while(top)push_down(q[top]),top--; for(int y=fa[x];!isroot(x);rotate(x),y=fa[x])if(!isroot(y)){ if((ch[fa[y]][0]==y)^(ch[y][0]==x))rotate(x); else rotate(y); }push_up(x); } void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),ch[x][1]=t,push_up(x);} void makeroot(int x){access(x),splay(x),rev[x]^=1;} void link(int x,int y){makeroot(x),fa[x]=y;} void cut(int x,int y){makeroot(x),access(y),splay(y),ch[y][0]=fa[x]=0;} void split(int x,int y){makeroot(x),access(y),splay(y);} int getlca(int x,int y){ for(int i=19;~i;i--){ if(y&(1<<i))x=F[x][i]; } return x; } int main(){ int cases; scanf("%d",&cases); while(cases--){ memset(fa,0,sizeof(fa)); memset(rev,0,sizeof(rev)); memset(size,0,sizeof(size)); memset(ch,0,sizeof(ch)); scanf("%d",&n); for(int i=2;i<=n;i++)scanf("%d",&F[i][0]); for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) F[i][j]=F[F[i][j-1]][j-1]; for(int i=1;i<=n;i++)scanf("%d",&a[i]),link(i+1,getlca(i,a[i])+1); scanf("%d",&m); while(m--){ scanf("%d%d",&op,&xx); if(op==1)split(1,xx+1),makeroot(xx+1),printf("%d\n",size[xx+1]-1); else scanf("%d",&yy),cut(xx+1,getlca(xx,a[xx])+1),a[xx]=yy,link(xx+1,getlca(xx,a[xx])+1); } for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) F[i][j]=0; } }
1010 Sequence (HDU 6395)
我们发现$\frac{n}{i}$最多有$\sqrt n$种取值
每种取值相同的,我们可以矩阵快速幂加速递推
就做完了
调到自闭
//By SiriusRen #include <bits/stdc++.h> using namespace std; #define int long long const int mod=1000000007; int cases,A,B,C,D,P,n; struct Matrix{ int a[3][3]; void init(){memset(a,0,sizeof(a));} }cng,fst,lst; Matrix operator*(Matrix a,Matrix b){ Matrix c;c.init(); for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; return c; } Matrix pow(Matrix a,int x){ Matrix temp;temp.init(); for(int i=0;i<3;i++)temp.a[i][i]=1; while(x){ if(x&1)temp=temp*a; a=a*a,x>>=1; } return temp; } void solve(){ for(int i=3,last;i<=min(P,n);i=last+1) { last=P/(P/i); last=min(last,n); fst.init(); fst.a[0][0]=lst.a[0][0],fst.a[1][0]=lst.a[1][0],fst.a[2][0]=P/i; Matrix inv=pow(cng,last-i+1); lst=inv*fst; } if(P<n){ P=max(P,2ll); fst.init(); fst.a[0][0]=lst.a[0][0],fst.a[1][0]=lst.a[1][0]; Matrix inv=pow(cng,n-P); lst=inv*fst; } } signed main(){ scanf("%lld",&cases); while(cases--){ scanf("%lld%lld%lld%lld%lld%lld",&A,&B,&C,&D,&P,&n); cng.init();cng.a[0][1]=1,cng.a[1][0]=C,cng.a[1][1]=D,cng.a[2][2]=1,cng.a[1][2]=1; lst.a[0][0]=A,lst.a[1][0]=B,lst.a[2][0]=P; solve(); printf("%lld\n",lst.a[1][0]); } }
1011 Swordsman (HDU 6396)
//By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=100500; int cases,n,k,v[6],cnt[N],Add[6],t[6],ans,addd[6][N]; struct Node{int wei,add,id;}w[6][N]; bool operator<(Node a,Node b){return a.wei<b.wei;} #define S 100000 char bf[S],*p1=bf,*p2=bf; #define nc() (p1==p2&&(p2=(p1=bf)+fread(bf,1,S,stdin),p2==p1)?-1:*p1++) inline int read(){ int x=0;char ch=nc();for(;ch<'0'||ch>'9';ch=nc()); for(;ch<='9'&&ch>='0';x=x*10+ch-48,ch=nc());return x; } int main(){ cases=read(); while(cases--){ memset(cnt,0,sizeof(cnt));ans=0; n=read(),k=read(); for(int i=1;i<=k;i++)v[i]=read(),t[i]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=k;j++) w[j][i].wei=read(),w[j][i].id=i; for(int j=1;j<=k;j++) w[j][i].add=read(),addd[j][i]=w[j][i].add; } for(int i=1;i<=k;i++)sort(w[i]+1,w[i]+1+n); while(1){ for(int i=1;i<=k;i++)Add[i]=0; for(int i=1;i<=k;i++){ while(w[i][t[i]].wei<=v[i]&&t[i]<=n){ cnt[w[i][t[i]].id]++; if(cnt[w[i][t[i]].id]==k){ ans++; for(int j=1;j<=k;j++){ Add[j]+=addd[j][w[i][t[i]].id]; } } t[i]++; } } for(int i=1;i<=k;i++)v[i]+=Add[i]; int flg=1; for(int i=1;i<=k;i++)if(Add[i])flg=0; if(flg)break; } printf("%d\n",ans); for(int i=1;i<=k;i++){ printf("%d",v[i]); if(i!=k)putchar(' '); }puts(""); } }