【NOIP2013】DAY1题解+代码

T1

傻逼快速幂,敲敲就过了。

我跟你们讲个笑话当时我以为这个数据范围过不了于是想出了求GCD再推规律什么的magic方法中途还咨询了某个学长。

然后怎么想都是不可做。

……直到我发现我昨年的代码一个傻逼快速幂就过了=A=

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
int n=0,m=0,k=0,x=0;
long long quick(int x,int y);
int main(void)
{
    freopen("circle.in","r",stdin);
    freopen("circle.out","w",stdout);
    scanf("%d%d%d%d",&n,&m,&k,&x);
    long long ans=quick(10,k);
    ans=ans*m%n;
    ans=(ans+x)%n;
    printf("%lld",ans);
    return 0;
}

long long quick(int x,int y)
{
    if(y==1)return x;
    int ins=y/2;
    long long tot=0ll;
    tot=quick(x,ins)%n;
    tot=tot*tot%n;
    if(y%2)tot=tot*x%n;
    return tot;
}
View Code

T2

排个序,离散化之后找逆序对即可。

这里要注意的是,我们先把两个数列离散化+排序之后,是找第二个数列里的数在第一个数列里出现的位置,然后对这个序列求逆序对。

我为了这个映射卖了很多蠢就不说了。

我会说因为我不想写归并于是用了树状数组求逆序对?

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
struct line
{
    int sum;
    int num;
};
line xl_a[100003],xl_b[100003];
int n=0,stack[100003]={0},top=0;
int mark[100003]={0},tree[100003]={0}; 
const int mod=99999997;
bool cmp(line a,line b);
bool kp(line a,line b);
int lowbit(int x);
int red(int x);
void add(int x);
int main(void)
{
    freopen("match.in","r",stdin);
    freopen("match.out","w",stdout); 
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&xl_a[i].sum),xl_a[i].num=i;
    sort(xl_a+1,xl_a+n+1,cmp);
    for(int i=1;i<=n;i++)xl_a[i].sum=i;
    
    for(int i=1;i<=n;i++)scanf("%d",&xl_b[i].sum),xl_b[i].num=i;
    sort(xl_b+1,xl_b+n+1,cmp);
    for(int i=1;i<=n;i++)xl_b[i].sum=i;
    
    
    sort(xl_b+1,xl_b+n+1,kp);
    for(int i=1;i<=n;i++)mark[i]=xl_a[xl_b[i].sum].num; 
    
    long long ans=0;
    
    for(int i=1;i<=n;i++)
    {
        ans+=red(n)-red(mark[i]);
        ans%=mod;
        add(mark[i]);
    } 
    printf("%d",ans);
    return 0;
}

bool cmp(line a,line b)
{
    if(a.sum<b.sum)return 1; 
    return 0;
} 

bool kp(line a,line b)
{
    if(a.num<b.num)return 1;
    return 0;
}

int lowbit(int x){return x&-x;}

int red(int x)
{
    int tot=0;
    while(x)
    {
        tot+=tree[x];
        tot%=mod;
        x-=lowbit(x);
    }
    return tot;
}

void add(int x)
{
    while(x<=n)
    {
        tree[x]++;
        tree[x]%=mod;
        x+=lowbit(x);
    }
}
View Code

T3

最大生成树+树上倍增标准模板

调了半小时发现我预处理写错了。

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
struct bian
{
    int x;
    int y;
    int v;
};
bian a[100003];//因为我们是存储双向边所以边数量x2
struct lb
{
    int u;
    int to;
    int val;
};
lb line[20003];
int head[10003]={0},fa[10003]={0},n=0,m=0,q=0;
int cnt_1=0,cnt_2=0,deep[10003]={0};
int beiz[10003][21]={0},value[10003][21]={0};
//最大生成树函数x3 
void kruskal();
int fid(int x);
void heb(int x,int y);
//树上倍增
void dfs(int nw);//确定树 
void pre(int x);//倍增预处理 
int ask(int x,int y);//查询两点之间的公共祖先
//乱七八糟的函数
void add(int f,int t,int val); 
bool cmp(bian A,bian B);
int main(void)
{
    freopen("truck.in","r",stdin);
    freopen("truck.out","w",stdout);
    scanf("%d%d",&n,&m);
    int b=0,c=0,d=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&b,&c,&d);
        cnt_1++;
        a[cnt_1].x=b,a[cnt_1].y=c,a[cnt_1].v=d;
        swap(b,c);
        cnt_1++;
        a[cnt_1].x=b,a[cnt_1].y=c,a[cnt_1].v=d;
    }
    sort(a+1,a+cnt_1+1,cmp);
    for(int i=1;i<=n;i++)fa[i]=i; 
    kruskal();
    memset(beiz,-1,sizeof(beiz));
    beiz[1][0]=1,value[1][0]=0x7ffffff,deep[1]=0; 
    dfs(1);
    pre(1);
    scanf("%d",&q);//我觉得是根节点的问题…… 
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&b,&c);
        if(beiz[b][0]==-1||beiz[c][0]==-1)
        {
            printf("-1
");
            continue;
        }
        printf("%d
",ask(b,c));
    }
    return 0; 
}
bool cmp(bian A,bian B)
{
    if(A.v>B.v)return 1;
    return 0;
}

int fid(int x)
{
    if(fa[x]==x)return x;
    fa[x]=fid(fa[x]);
    return fa[x];
}

void heb(int x,int y)
{
    fa[x]=y;
    return;
}

void kruskal()
{
    int cho=0,f_x=0,f_y=0;
    for(int i=1;i<=cnt_1;i++)
    {
        if(cho==n-1)break;
        f_x=fid(a[i].x);
        f_y=fid(a[i].y); 
        if(f_x==f_y)continue;
        cho++;
        add(a[i].x,a[i].y,a[i].v);
        add(a[i].y,a[i].x,a[i].v);
        heb(f_x,f_y);
    } 
    return;    
}

void add(int f,int t,int val)
{
    line[++cnt_2].u=t;
    line[cnt_2].to=head[f];
    line[cnt_2].val=val;
    head[f]=cnt_2;
    return;
}

void dfs(int nw)
{
    if(nw>n)return;
    int next=0; 
    for(int i=head[nw];i>0;i=line[i].to)
    {
        next=line[i].u;
        if(next==beiz[nw][0])continue;
        beiz[next][0]=nw;
        value[next][0]=line[i].val;
        deep[next]=deep[nw]+1;
        dfs(next);
    }
    return;
}

void pre(int nw)
{
    if(nw>=20)return;
    for(int i=1;i<=n;i++)
    {
        beiz[i][nw]=beiz[beiz[i][nw-1]][nw-1];
        value[i][nw]=min(value[i][nw-1],value[beiz[i][nw-1]][nw-1]);
    }
    pre(nw+1); 
    return;
}

int ask(int x,int y) 
{
    if(deep[x]<deep[y])swap(x,y);
    int ans=0x7fffffff;
    for(int i=19;i>=0;i--)if(deep[x]-(1<<i)>=deep[y])ans=min(ans,value[x][i]),x=beiz[x][i];
    if(x==y)return ans;
    for(int i=19;i>=0;i--)
    {
        if(beiz[x][i]!=beiz[y][i])
        {
            ans=min(ans,value[x][i]);
            x=beiz[x][i];
            ans=min(ans,value[y][i]);
            y=beiz[y][i];
        }
    }
    ans=min(ans,value[x][0]);
    ans=min(ans,value[y][0]);
    return ans;
}
View Code
原文地址:https://www.cnblogs.com/CYWer/p/6054662.html