noip2013

无人久伴 提交于 2019-11-28 18:32:16

D1:

T1:快速幂

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#define LL long long 
using namespace std;
LL n,m,k,x;
inline LL quickpow(LL a,LL b){//a^b %n
    LL ans=1ll;
    while(b){
        if(b&1)ans=ans*a%n;

        a=a*a%n;            
        b>>=1;
    }
    return ans;
}
int main(){
//freopen("circle.in","r",stdin);
//freopen("circle.out","w",stdout);
    
scanf("%lld%lld%lld%lld",&n,&m,&k,&x);

printf("%lld",(x%n+m*quickpow(10ll,k)%n)%n);
    
    return 0;
}

T2:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
const int maxn=1e5+5;
const int P=99999997;
int n;
int a[maxn],b[maxn],to[maxn],ans;
map<int ,int >pa;
map<int ,int >pb;

int sum[maxn];
inline int lowbit(int x){return x&(-x);}
inline int query(int p){
    int ans=0;
    while(p){
        ans+=sum[p];
        p-=lowbit(p);
    }
    return ans;
}
inline void modify(int p){
    while(p<=n){
        sum[p]++;
        p+=lowbit(p);
    }
}
int main(){
    //freopen("match.in","r",stdin);
    //freopen("match.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        pa[a[i]]=i;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&b[i]);
        pb[b[i]]=i;
    }
    sort(a+1,a+n+1);
    sort(b+1,b+n+1);
    /*  这里用到了排序不等式,(a-b)^2==a^2+b^2-2ab,  找到一个排列 s.t. -2ab  max   自然想到排序不等式  正序和 <= 乱序和 <= 逆序和  */
    for(int i=1;i<=n;i++){
        to[ pa[a[i]] ]=pb[b[i]];
    }
    
    memset(sum,0,sizeof(sum));
    ans=0;

    for(int i=n;i;i--){//由于是相邻的两个火柴交换,直接求逆序对
        ans=(ans+query(to[i]-1))%P;
        modify(to[i]);
    }
    printf("%d\n",ans);
    return 0;
}

T3:

这题挺不好想,但是从部分分出发

30` && 60` 有向图两点间最小边最大,二分答案,O(q *log( m)* m )

但是其中填边的步骤可以省略,O(q*m)--------->kruscal 第一个使得两点联通的 边就是答案

100` 我们发现 每个询问都会填边太麻烦,然后我们想,推出两个性质

1:

如果该边是答案,那么他一定在该图的最大生成树中(反证法)

2:

如果该边是答案,那么两点联通 当且仅当 该边被添加(反证法)

 

于是就得到了满分算法,最大生成树+LCA最小边

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
#define LL long long 
using namespace std;
const int maxn=1e4+5;
const int maxm=5e4+5;
struct Edge{
    int u;
    int v;
    int w;
    const bool operator<(const Edge &x)const{return w<x.w;}
    inline void read(){
        scanf("%d%d%d",&u,&v,&w);
    }
}e[maxm];
int n,m,q;

int father[maxn];
int find(int x){return father[x]==x ? x : father[x]=find(father[x]);}//dsu

int fst[maxn],nxt[maxm<<1],to[maxm<<1],w[maxm<<1],edge_count;
inline void add(int x,int y,int z){
    edge_count++;
    to[edge_count]=y;
    w[edge_count]=z;
    nxt[edge_count]=fst[x];
    fst[x]=edge_count;
}

inline void kruscal(){
    for(int i=1;i<=n;i++)father[i]=i;//dsu_init
    
    sort(e+1,e+m+1);
    
    for(int i=m;i;i--){//鏈€澶х敓鎴愭爲
        int fu=find(e[i].u);int fv=find(e[i].v);
        if(fu==fv)continue;
        father[fu]=fv;
        
        add(e[i].u,e[i].v,e[i].w);
        add(e[i].v,e[i].u,e[i].w);                        
    }
}
const int INF=0x3f3f3f3f;

int f[maxn][50],g[maxn][50],deep[maxn],tre[maxn],temp;
void dfs(int u,int fa){
    tre[u]=temp;

    deep[u]=deep[fa]+1;
    for(int i=1;i<30;i++){
        f[u][i]=f[ f[u][i-1] ][i-1];
        g[u][i]=min(g[ f[u][i-1] ][i-1],g[u][i-1]);
    }

    for(int i=fst[u];i;i=nxt[i]){
        int v=to[i];
        if(v==fa)continue;
        f[v][0]=u;
        g[v][0]=w[i];
        dfs(v,u);
    }
}
inline void LCA_init(){
    memset(g,0x3f,sizeof(g));
    for(int i=1;i<=n;i++)if(!deep[i]){
        temp++;        
        dfs(i,0);
    }
}

inline int LCA(int x,int y){
    int ans=INF;

    if(deep[x]<deep[y])swap(x,y);
    for(int i=29;i>=0;i--){
        if(deep[f[x][i]]>=deep[y]){
            ans=min(ans,g[x][i]);
            x=f[x][i];
        }            
    }
    if(x==y)return ans;
    for(int i=29;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            ans=min(ans,min(g[x][i],g[y][i]));
            x=f[x][i];y=f[y][i];            
        }
    }
    ans=min(ans,min(g[x][0],g[y][0]));
    return ans;
}
int main(){
//freopen("truck.in","r",stdin);
//freopen("truck.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        e[i].read();
    }
    kruscal();
    LCA_init();
    
    scanf("%d",&q);    
    for(int i=1,x,y;i<=q;i++){
        scanf("%d%d",&x,&y);
        if(tre[x]!=tre[y])printf("-1\n");
        else printf("%d\n",LCA(x,y));
    }
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!