SDOI 2016 Round1 Day1

储能表

/*
引自zyz大佬的数学思想 
*/
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;

#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif

ll k;int T,p;
int calc(ll x,ll i,ll j){
    if(i<j) swap(i,j);
    x/=i;
    x*=i;
    j%=p;
    ll l=max(0LL,x-k);
    ll r=max(0LL,x+i-k);
    ll ans=(l+r-1);
    if(!(ans&1)){
        ans=(ans>>1)%p;
        ans=(ans*((r-l)%p))%p;
    }
    else{
        ans=ans%p;
        ans=(ans*((r-l>>1)%p))%p;
    }
    return ans*j%p;
}
int solve(ll n,ll m){
    ll ans=0;
    for(ll i=1LL<<60,x=0;i;i>>=1){
        if(n&i){
            for(ll j=1LL<<60,y=0;j;j>>=1){
                if(m&j){
                    ans+=calc(x^y,i,j);
                    ans%=p;
                    y+=j;
                }
            }
            x+=i;
        }
    }
    return ans;
}
int main(){
    for(scanf("%d",&T);T--;){
        ll n,m;
        scanf(LL LL LL LL,&n,&m,&k,&p);
        printf("%d\n",solve(n,m));
    }
    return 0;
}

 

 

数字配对

/*
二分图-->费用流
*/
#include<cstdio>
#include<cstdlib>
#include<iostream>
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
using namespace std;
typedef long long i64;
const int N=4005;
const int M=5e5+5;
const i64 inf=10000000000000LL;
struct edge{int v,next;i64 cap,cost;}e[M];int tot=1,head[N];
int n,m,S,T,q[N],prev[N];bool vis[N];
i64 a[N],b[N],c[N];
i64 answ,ansf,dis[N];
void add(int x,int y,i64 z,i64 cost){
    e[++tot].v=y;e[tot].cap=z;e[tot].cost=cost;e[tot].next=head[x];head[x]=tot;
    e[++tot].v=x;e[tot].cap=0;e[tot].cost=-cost;e[tot].next=head[y];head[y]=tot;
}
bool spfa(){
    for(int i=S;i<=T;i++) vis[i]=0,dis[i]=-inf;
    unsigned short h=0,t=1;q[t]=S;dis[S]=0;
    while(h!=t){
        int x=q[++h];vis[x]=0;
        for(int i=head[x];i;i=e[i].next){
            if(e[i].cap&&dis[e[i].v]<dis[x]+e[i].cost){
                dis[e[i].v]=dis[x]+e[i].cost;
                prev[e[i].v]=i;
                if(!vis[e[i].v]){
                    vis[e[i].v]=1;
                    //if(dis[e[i].v]>dis[x]){
                    //  q[h--]=e[i].v;
                    //}
                    //else{
                        q[++t]=e[i].v;
                    //}
                }
            }
        }
    }
    return answ+dis[T]>=0;   
}
void augment(){
    i64 flow=inf;
    if(dis[T]<0) flow=answ/(-dis[T]);
    for(int i=T;i!=S;i=e[prev[i]^1].v){
        flow=min(flow,e[prev[i]].cap);
    }
    for(int i=T;i!=S;i=e[prev[i]^1].v){
        e[prev[i]].cap-=flow;
        e[prev[i]^1].cap+=flow;
    }
    ansf+=flow;
    answ+=flow*dis[T];
}
i64 fpow(i64 a,i64 p,i64 mod){
    i64 res=1;
    for(;p;p>>=1,a=a*a%mod) if(p&1) res=res*a%mod;
    return res;
}
bool judge(i64 x){
    if(x<2) return 0;
    if(x==2) return 1;
    if(x&1^1) return 0;
    i64 a,t;
    for(int i=1;i<=10;i++){
        a=rand()%M;
        if(a>=x&&a%x==0) continue;
        t=fpow(a,x-1,x);
        if(t!=1) return 0;
    } 
    return 1;
}
int main(){
    scanf("%d",&n);S=0,T=n<<1|1;
    for(int i=1;i<=n;i++) scanf(LL,&a[i]);
    for(int i=1;i<=n;i++){
        scanf(LL,&b[i]);
        add(S,i,b[i],0);
        add(i+n,T,b[i],0);
    }
    for(int i=1;i<=n;i++) scanf(LL,&c[i]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==j) continue;
            if(a[j]&&!(a[i]%a[j])&&judge(a[i]/a[j])){
                add(i,j+n,inf,c[i]*c[j]);
            }
            if(a[i]&&!(a[j]%a[i])&&judge(a[j]/a[i])){
                add(i,j+n,inf,c[i]*c[j]);
            }
        }
    }
    while(spfa()) augment();
    printf(LL,ansf/2);
    return 0;
}

 

游戏

/*
树链剖分+树上差分
*/
#include<cstdio>
#include<algorithm>
using namespace std;
 
#define lc k<<1
#define rc k<<1|1
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
 
typedef long long ll;
const ll inf=123456789123456789LL;
const int N=1e5+5;
struct line{ll a,b;};
struct edge{int v,w,next;}e[N<<1];int tot,head[N];
struct sgt{
    ll mn;
    line a;
    bool tag;
    sgt(){mn=inf;tag=0;}
}tr[N<<2];
int n,m,fa[N],son[N],siz[N],pos[N],top[N],dep[N],q[N];
ll ans,dfn[N],dis[N];
void add(int x,int y,int z){
    e[++tot].v=y;e[tot].w=z;e[tot].next=head[x];head[x]=tot;
    e[++tot].v=x;e[tot].w=z;e[tot].next=head[y];head[y]=tot;
}
void bfs(){
    int h=0,t=1;q[t]=1;dep[1]=1;fa[1]=1;
    while(h!=t){
        int x=q[++h];
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(v!=fa[x]){
                fa[v]=x;
                dep[v]=dep[x]+1;
                dis[v]=dis[x]+e[i].w;
                q[++t]=v;
            }
        }
    }
    for(int j=n;j;j--){
        int x=q[j];siz[x]=1;son[x]=0;
        for(int i=head[x];i;i=e[i].next){
            int v=e[i].v;
            if(fa[v]==x){
                siz[x]+=siz[v];
                if(siz[son[x]]<siz[v]) son[x]=v;
            }
        }
    }
    int bfs_cnt=0;
    for(int j=1;j<=n;j++){
        int x=q[j];
        if(!pos[x]){
            for(int y=x;y;y=son[y]){
                pos[y]=++bfs_cnt;
                dfn[bfs_cnt]=dis[y];
                top[y]=x;
            }
        }
    }
}
int lca(int x,int y){
    for(;top[x]!=top[y];x=fa[top[x]]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
    }
    return dep[x]<dep[y]?x:y;
}
ll get(line a,ll x){
    return a.a*x+a.b;
}
void change(int k,int l,int r,int opl,int opr,line a){
    int mid=l+r>>1;
    if(opl<=l&&r<=opr){
        tr[k].mn=min(tr[k].mn,min(get(a,dfn[l]),get(a,dfn[r])));
        if(!tr[k].tag){
            tr[k].tag=1;tr[k].a=a;
            return ;
        }
        if(l==r){
            if(get(a,dfn[l])<get(tr[k].a,dfn[l]))tr[k].a=a;
            return ;
        }
        bool b0=get(a,dfn[l])<get(tr[k].a,dfn[l]);
        bool b1=get(a,dfn[mid])<get(tr[k].a,dfn[mid]);
        bool b2=get(a,dfn[r])<get(tr[k].a,dfn[r]);
        if(!b0&&!b2) return ;
        if(b0&&b2){
            tr[k].a=a;
            return ;
        }
        if(b1){
            swap(a,tr[k].a);
            b0^=1;b2^=1;
        }
        if(b0) change(lc,l,mid,opl,opr,a);
        if(b2) change(rc,mid+1,r,opl,opr,a);
        return ;
    }
    if(opl<=mid) change(lc,l,mid,opl,opr,a);
    if(mid+1<=opr) change(rc,mid+1,r,opl,opr,a);
    tr[k].mn=min(tr[k].mn,min(tr[lc].mn,tr[rc].mn));
}
void query(int k,int l,int r,int opl,int opr){
    if(opl<=l&&r<=opr){
        ans=min(ans,tr[k].mn);
        return ;
    }
    if(tr[k].tag){
        ans=min(ans,min(get(tr[k].a,dfn[max(l,opl)]),get(tr[k].a,dfn[min(r,opr)])));
    }
    int mid=l+r>>1;
    if(opl<=mid) query(lc,l,mid,opl,opr);
    if(mid+1<=opr) query(rc,mid+1,r,opl,opr);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,x,y,z;i<n;i++){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
    }
    bfs();
    for(int i=1,opt,x,y,z;i<=m;i++){
        scanf("%d",&opt);
        if(opt&1){
            ll a,b;
            scanf("%d%d",&x,&y);
            scanf(LL LL ,&a,&b);
            z=lca(x,y);
            ll Ax=-a,Bx=a*dis[x]+b;
            ll Ay=a,By=a*(-2*dis[z]+dis[x])+b;
            for(;dep[top[x]]>dep[z];x=fa[top[x]]){
                change(1,1,n,pos[top[x]],pos[x],(line){Ax,Bx});
            }
            for(;dep[top[y]]>dep[z];y=fa[top[y]]){
                change(1,1,n,pos[top[y]],pos[y],(line){Ay,By});
            }
            if(x!=z) change(1,1,n,pos[z],pos[x],(line){Ax,Bx});
            else if(y!=z) change(1,1,n,pos[z],pos[y],(line){Ay,By});
            else change(1,1,n,pos[z],pos[z],(line){Ax,Bx});
        }
        else{
            scanf("%d%d",&x,&y);
            ans=inf;
            z=lca(x,y);
            for(;dep[top[x]]>dep[z];x=fa[top[x]]){
                query(1,1,n,pos[top[x]],pos[x]);
            }
            for(;dep[top[y]]>dep[z];y=fa[top[y]]){
                query(1,1,n,pos[top[y]],pos[y]);
            }
            if(x!=z) query(1,1,n,pos[z],pos[x]);
            else if(y!=z) query(1,1,n,pos[z],pos[y]);
            else query(1,1,n,pos[z],pos[z]);
            printf(LL "\n",ans);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/shenben/p/6403145.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值