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("");
    }
}

 

posted @ 2018-08-14 10:59 SiriusRen 阅读(...) 评论(...) 编辑 收藏