开学后的第一篇

漫长(并不)而充实(未必)的寒假终于结束了。又是新学期的竞赛课程。看着满机房的学弟学妹们,心中澎湃万分。

回归正题,回来第三天了,捡这三天做的比较好的题目写新学期的第一篇博客,勉励自己在OI的不归路上再接再厉。

并不难(异常简单)的一题,但第一时间硬是没想到——原因是在假期听了许多节数据结构课,导致看到区间询问就想到线段树,花了5分钟打完后发现不对,10亿的范围连数组都开不出来。正解应该是:排序,二分查找一个询问中两端的位置,相减的区间内谷堆数量。代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

int n,q,a[100100];
int comp(const int&a,const int&b){
    return a<b;
}
int search(int l,int r){
    int la=1;
    int ra=n;
    int mida=(la+ra)/2;
    while(!(a[mida]>=l&&a[mida-1]<l)){
        if(a[mida]>=l){
            ra=mida-1;
            mida=(la+ra)/2;
        }
        else{
            la=mida+1;
            mida=(la+ra)/2;
        }
        //cout<<la<<" "<<ra<<endl;
        if(la>=ra)break;
    }
    int lb=1;
    int rb=n;
    int midb=(lb+rb)/2;
    while(!(a[midb]<=r&&a[midb+1]>r)){
        if(a[midb]<=r){
            lb=midb+1;
            midb=(lb+rb)/2;
        }
        else{
            rb=midb-1;
            midb=(lb+rb)/2;
        }
        //cout<<lb<<" "<<rb<<endl;
        if(lb>=rb)break;
    }
    return midb-mida+1;
}
int main(){
    freopen("haybales.in","r",stdin);
    freopen("haybales.out","w",stdout); 
    cin>>n>>q;
    for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    sort(a+1,a+n+1,comp);
    for(int i=1;i<=q;++i){
        int l,r;
        scanf("%d%d",&l,&r);
        if(l>a[n]||r<a[1]){
            cout<<0<<endl;
            continue;
        }
        printf("%d\n",search(l,r));
    }
    return 0;
}

上面这道题目给出的教训是,不要想当然。

乍一看都能想到N方的算法。细想不难发现有用的字段最多有26乘以26=676种,因此可以做一个有676个点的图。以城市名称的前两位为起点,州代码为终点加单向边,最后两两统计点与点之间两种单向边的乘积,累加即可。(PS:题目描述不是很明确,按照测试数据如果有两个ABAB的城市,不视为互有特殊关系)。代码如下(。。。尴尬,代码好像被我搞丢了,不管了,下一题)

第一眼递推,但只能得到30分。正解须涉及到矩阵乘法。(可以在网上找找“矩阵乘法求斐波那契数列”),原理类似。乘积部分应用快速幂。代码如下

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include <list>            //STL 线性列表容器
#include <map>       //STL 映射容器
#include <queue>      //STL 队列容器
#include <set>       //STL 集合容器
#include <stack>      //STL 堆栈容器
using namespace std;

inline int read(){
    char ch=getchar();
    int re=0;
    bool fl=1;
    if (ch=='-'){
        re=0;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        re=re*10+ch-'0';
        ch=getchar();
    }
    return fl?re:-re;
}

long long bas[4][4],ans[4][4],now[4][4],n,t,c;
void getjz(int k){
    if(k==1){
        for(int i=1;i<=3;++i)
        for(int j=1;j<=3;++j)ans[i][j]=bas[i][j];
        return;
    }
    if(k%2==0){
        getjz(k/2);
        now[1][1]=(ans[1][1]*ans[1][1]%c+ans[1][2]*ans[2][1]%c+ans[1][3]*ans[3][1]%c)%c;
        now[1][2]=(ans[1][1]*ans[1][2]%c+ans[1][2]*ans[2][2]%c+ans[1][3]*ans[3][2]%c)%c;
        now[1][3]=(ans[1][1]*ans[1][3]%c+ans[1][2]*ans[2][3]%c+ans[1][3]*ans[3][3]%c)%c;
        now[2][1]=(ans[2][1]*ans[1][1]%c+ans[2][2]*ans[2][1]%c+ans[2][3]*ans[3][1]%c)%c;
        now[2][2]=(ans[2][1]*ans[1][2]%c+ans[2][2]*ans[2][2]%c+ans[2][3]*ans[3][2]%c)%c;
        now[2][3]=(ans[2][1]*ans[1][3]%c+ans[2][2]*ans[2][3]%c+ans[2][3]*ans[3][3]%c)%c;
        now[3][1]=(ans[3][1]*ans[1][1]%c+ans[3][2]*ans[2][1]%c+ans[3][3]*ans[3][1]%c)%c;
        now[3][2]=(ans[3][1]*ans[1][2]%c+ans[3][2]*ans[2][2]%c+ans[3][3]*ans[3][2]%c)%c;
        now[3][3]=(ans[3][1]*ans[1][3]%c+ans[3][2]*ans[2][3]%c+ans[3][3]*ans[3][3]%c)%c;
        for(int i=1;i<=3;++i)
        for(int j=1;j<=3;++j){
            //cout<<now[i][j]<<" ";
            //if(j==3)cout<<endl;
            ans[i][j]=now[i][j];
        }
        return;
    }
    if(k%2!=0){
        getjz(k-1);
        now[1][1]=(ans[1][1]*bas[1][1]%c+ans[1][2]*bas[2][1]%c+ans[1][3]*bas[3][1]%c)%c;
        now[1][2]=(ans[1][1]*bas[1][2]%c+ans[1][2]*bas[2][2]%c+ans[1][3]*bas[3][2]%c)%c;
        now[1][3]=(ans[1][1]*bas[1][3]%c+ans[1][2]*bas[2][3]%c+ans[1][3]*bas[3][3]%c)%c;
        now[2][1]=(ans[2][1]*bas[1][1]%c+ans[2][2]*bas[2][1]%c+ans[2][3]*bas[3][1]%c)%c;
        now[2][2]=(ans[2][1]*bas[1][2]%c+ans[2][2]*bas[2][2]%c+ans[2][3]*bas[3][2]%c)%c;
        now[2][3]=(ans[2][1]*bas[1][3]%c+ans[2][2]*bas[2][3]%c+ans[2][3]*bas[3][3]%c)%c;
        now[3][1]=(ans[3][1]*bas[1][1]%c+ans[3][2]*bas[2][1]%c+ans[3][3]*bas[3][1]%c)%c;
        now[3][2]=(ans[3][1]*bas[1][2]%c+ans[3][2]*bas[2][2]%c+ans[3][3]*bas[3][2]%c)%c;
        now[3][3]=(ans[3][1]*bas[1][3]%c+ans[3][2]*bas[2][3]%c+ans[3][3]*bas[3][3]%c)%c;
        for(int i=1;i<=3;++i)
        for(int j=1;j<=3;++j){
            //cout<<now[i][j]<<" ";
            //if(j==3)cout<<endl;
            ans[i][j]=now[i][j];
        }
        return;
    }
}
int main(){
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    c=1000000007;
    scanf("%d",&t);
    bas[1][1]=1;
    bas[1][2]=0;
    bas[1][3]=1;
    bas[2][1]=1;
    bas[2][2]=0;
    bas[2][3]=0;
    bas[3][1]=0;
    bas[3][2]=1;
    bas[3][3]=0;
    for(int i=1;i<=t;++i){
        int k;
        scanf("%d",&k);
        for(int i=1;i<=3;++i)
        for(int j=1;j<=3;++j)ans[i][j]=0;
        if(k>3){
            getjz(k-3);
            //int final=
            printf("%d\n",(ans[1][1]+ans[1][2]+ans[1][3])%c);
        }
        else printf("%d\n",1);
    }

    return 0;
}

最后跑一个稍微复杂一点的

第一眼DP,但是超规模了,60分。题干中说这不是一个简单的最短路问题——那就是不简单的最短路问题。将每个点拆成两个点即可。注意点X,Y相通时,是X与Y+N相连,X+N与Y相连。还有,X与X+N之间有距离。最短路我用的是SPFA,没有负边权的情况下也可用迪杰斯特拉(Dijkstra)。代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include <list>            //STL 线性列表容器
#include <map>       //STL 映射容器
#include <queue>      //STL 队列容器
#include <set>       //STL 集合容器
#include <stack>      //STL 堆栈容器
using namespace std;

queue<int>q1;
long long d[10100];
int m,n,lnum,head[10100],dis[10100];
bool tt[10100];
inline int read(){
    char ch=getchar();
    int re=0;
    bool fl=1;
    if (ch=='-'){
        re=0;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        re=re*10+ch-'0';
        ch=getchar();
    }
    return fl?re:-re;
}

struct star{
    int type;
    int w;
    int s;
};  star c[10100];

struct line{
    int power;
    int goal;
    int next;
};  line ll[100010];

int main(){
    freopen("holes.in","r",stdin);
    freopen("holes.out","w",stdout);
    n=read(); m=read();
    for(int i=1;i<=n;++i){
        int x; x=read();
        c[i].type=x;
        c[i+n].type=abs(1-x);
    }
    for(int i=1;i<=n;++i){
        int x; x=read();
        c[i].w=x; c[i+n].w=x;
    }
    for(int i=1;i<=n;++i){
        int x; x=read();
        c[i].s=x; c[i+n].s=x;
    }
    lnum=0;
    for(int i=1;i<=n;++i){
        if(c[i].type==0){
            lnum++;
            ll[lnum].goal=i+n;
            ll[lnum].power=0;
            ll[lnum].next=head[i];
            head[i]=lnum;
            lnum++;
            ll[lnum].goal=i;
            ll[lnum].power=c[i].s;
            ll[lnum].next=head[i+n];
            head[i+n]=lnum;
        }
        else{
            lnum++;
            ll[lnum].goal=i+n;
            ll[lnum].power=c[i].s;
            ll[lnum].next=head[i];
            head[i]=lnum;
            lnum++;
            ll[lnum].goal=i;
            ll[lnum].power=0;
            ll[lnum].next=head[i+n];
            head[i+n]=lnum;
        }
    }
    for(int i=1;i<=m;++i){
        int x,y,z;
        x=read(); y=read(); z=read();
        if(c[x].type==c[y].type){
            //cout<<x<<" "<<y<<endl;
            lnum++;
            ll[lnum].goal=y+n;
            ll[lnum].power=z;
            ll[lnum].next=head[x];
            head[x]=lnum;
            lnum++;
            ll[lnum].goal=y;
            ll[lnum].power=z;
            ll[lnum].next=head[x+n];
            head[x+n]=lnum;
        } 
        if((c[x].type==1)&&(c[y].type==0)){
            lnum++;
            ll[lnum].goal=y+n;
            ll[lnum].power=z+abs(c[x].w-c[y].w);
            ll[lnum].next=head[x];
            head[x]=lnum;
            lnum++;
            ll[lnum].goal=y;
            ll[lnum].power=max(0,z-abs(c[x].w-c[y].w));
            ll[lnum].next=head[x+n];
            head[x+n]=lnum;
        }
        if((c[x].type==0)&&(c[y].type==1)){
            lnum++;
            ll[lnum].goal=y+n;
            ll[lnum].power=max(0,z-abs(c[x].w-c[y].w));
            ll[lnum].next=head[x];
            head[x]=lnum;
            lnum++;
            ll[lnum].goal=y;
            ll[lnum].power=z+abs(c[x].w-c[y].w);
            ll[lnum].next=head[x+n];
            head[x+n]=lnum;
        }
    }
    //for(int i=1;i<=2*n;++i)cout<<c[i].w<<" ";
    //cout<<endl;
    /*for(int i=1;i<=2*n;++i){
        int p=head[i];
        while(p!=0){
            printf("%d %d %d\n",i,ll[p].goal,ll[p].power);
            p=ll[p].next;
        }
    }*/
    
    for(int i=2;i<=2*n;++i)dis[i]=1147483641;
    dis[1]=0;
    q1.push(1);
    tt[1]=true;
    while(!q1.empty()){
        int k=q1.front(); q1.pop(); tt[k]=false;
        int p=head[k];
        while(p!=0){
            if(dis[ll[p].goal]>dis[k]+ll[p].power){
                dis[ll[p].goal]=dis[k]+ll[p].power;
                if(tt[ll[p].goal]==false){
                    tt[ll[p].goal]==true;
                    q1.push(ll[p].goal);
                }
            }
            p=ll[p].next;
        }
    }
    //for(int i=1;i<=2*n;++i)cout<<dis[i]<<" ";
    printf("%d",min(dis[n],dis[2*n]));
    return 0;
}

最后勉励自己:路漫漫其修远兮,吾将上下而求索。

 

posted @ 2017-02-08 13:59  1293241756  阅读(113)  评论(0编辑  收藏  举报