开学后的第一篇
漫长(并不)而充实(未必)的寒假终于结束了。又是新学期的竞赛课程。看着满机房的学弟学妹们,心中澎湃万分。
回归正题,回来第三天了,捡这三天做的比较好的题目写新学期的第一篇博客,勉励自己在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; }
最后勉励自己:路漫漫其修远兮,吾将上下而求索。