10.22考试总结

来源:互联网 发布:cdma是什么网络模式 编辑:程序博客网 时间:2024/06/06 23:50

先说今天考试比较水很多dalao都Ak了,然后我是真的很想抽自己,下面请看;

1.斐波那契数

    题目大意:给一个数,判断它是不是两个斐波那契数的乘机(n<=100000000);

    感想:很容易看出来f[45],就超1e9了,然后n方枚举就ok了,我日常卡第一题,花了一个半小时,硬是找了个规律,写了个logn的东西,首先可以二分求出f[l]<=n<=f[r],然后你可以发现它们可以是和f[1]的乘积,而这中间的斐波那契数的乘积都一定是由f(l+2-i)*f(i)得来的,这样在(l+2)/2到l枚举,因为它不超过45,所以一半大概是20几,差不多也是log级别的,所以玄学的花了1个半小时写出来,我也是醉了。

# include <iostream># include <cstdio># include <cstring># include <algorithm># include <cmath># include <list>using namespace std;typedef long long ll;ll read(){ll f=1,i=0;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}return f*i;}ll f[1000],x;int main(){f[0]=0;f[1]=1;for(int i=2;i<=100;++i)         f[i]=f[i-1]+f[i-2];int t=read();while(t--){x=read();int l=1,r=50;while(l<=r){int mid=l+r>>1;if(f[mid]<=x) l=mid+1;else r=mid-1;}int L,R,flag=0;if(x==f[l]||x==f[r]) flag=1;R=r-1;if((2+r)&1) L=(2+r)/2+1;else L=(2+r)/2;for(int i=L;i<=R;++i)    if(f[i]*f[r+2-i]==x) flag=1;if(flag) {puts("Yes");}else puts("No");}}
2.一样远

   题目大意:给一棵树,在给两个点a,b,求树上到它们距离相等的点有多少个。

   感想:因为第一题的智障,我还剩两个小时刚后两道题,然后这一道题花了50分钟写完,lca+倍增嘛,过了样例以及手造的几组大样例,感觉很稳,因为时间不够也懒得打对拍了,于是成功wa的只剩十分。正解:求lca,然后倍增找到中点,中点中含有a,b两点的子树上的点都不能选于是减去,剩下的就是答案,注意lcd就是中点的时候要特判,而且是有可能两个点一个在上一个在下,或是两个都在下,别问我怎么知道的,说来都是qaq。

# include <iostream># include <cstdio># include <cstring># include <algorithm># include <cmath># include <list>using namespace std;typedef long long ll;int read(){int f=1,i=0;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}return f*i;}const int N=100005;struct node{int v;node *next;}E[N<<2],*first[N],*cnt=E;int n,m,x,y,z,q,lenth,son;int dis[N],dep[N],fa[N][20],size[N];bool vis[N]={false};inline void AddEdge(int x,int y){node *p=++cnt;p->next=first[x];first[x]=p;p->v=y;}inline void DFS(int u){vis[u]=true;size[u]=1;for(node *p=first[u];p;p=p->next){if(!vis[p->v]){dis[p->v]=dis[u]+1;dep[p->v]=dep[u]+1;fa[p->v][0]=u;DFS(p->v);size[u]+=size[p->v];}}}inline void pre(){for(int j=1;j<=17;++j)    for(int i=1;i<=n;++i)        if(fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1];}int LCA(int x,int y){int len=dep[x]-dep[y];for(int i=17;i>=0;--i){if(len>=(1<<i)){len-=(1<<i);x=fa[x][i];}}if(x==y) return x;for(int i=17;i>=0;--i){if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}}return fa[x][0];}int update(int len,int x){for(int i=17;i>=0;--i){if(len>=(1<<i)){len-=(1<<i);x=fa[x][i];}}return x;}int main(){n=read();for(int i=1;i<n;++i){x=read(),y=read();AddEdge(x,y),AddEdge(y,x);}DFS(1);pre();m=read();while(m--){x=read(),y=read();if(x==y){printf("%d\n",n);continue;}if(dep[x]<dep[y])swap(x,y);int lca=LCA(x,y);son=0;lenth=dis[x]+dis[y]-2*dis[lca];if(lenth&1) printf("0\n");else{lenth>>=1;int fx,fy;fx=update(lenth-1,x);fy=update(lenth-1,y);if(dep[x]-dep[lca]==lenth) {cout<<n-size[fx]-size[fy]<<endl;continue;}cout<<size[fa[fx][0]]-size[fx]<<endl;}}}
3.拆网线

    题目大意:给一棵树,给一个点数k,要求保证k点中一个点至少与另一个点有一条边,求最少保留几条边;

    感想:因为前两道题的智障,于是想了会,发现就是一个贪心嘛,两两配对下来一定最优,于是拓扑排序,每次选入度最小的与它对面的点匹配,走一遍就行了,于是复杂度o(n),输出时如果要求的点数大于两个点的对数(num)乘2,则输出k-num*2+num,若大于则输出(k+1)/2,而我智障的直接输出了num,我可能是吃了假药吧。

# include <iostream># include <cstdio># include <cstring># include <algorithm># include <cmath># include <list># include <queue>using namespace std;typedef long long ll;int read(){int f=1,i=0;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){i=(i<<3)+(i<<1)+ch-'0';ch=getchar();}return f*i;}const int N=100005;struct node{int u,v,next;}E[N<<2];int t,n,m,x,y,k,cnt,r[N],mark[N],first[N];inline void initial(){     cnt=0;     memset(mark,0,sizeof(mark));     memset(r,0,sizeof(r));     memset(first,0,sizeof(first));     memset(E,0,sizeof(E));}inline void AddEdge(int x,int y){    E[++cnt].next=first[x];    first[x]=cnt;    E[cnt].v=y;    r[x]++,r[y]++;}int main(){        t=read();while(t--){ initial(); n=read(),k=read(); for(int i=1;i<n;++i) { x=read(); AddEdge(x,i+1); AddEdge(i+1,x); } queue<int>q; for(int i=1;i<=n;++i) if(r[i]==2) q.push(i); while(!q.empty()) { int now=q.front();q.pop(); for(int i=first[now];i;i=E[i].next) { int v=E[i].v;if(!mark[now]&&!mark[v])     mark[now]=1,mark[v]=2; r[v]-=2;if(r[v]==2) q.push(v); } } int num=0; for(int i=1;i<=n;++i) if(mark[i]==1) num++; if(k<=num*2) printf("%d\n",(k+1)/2); else printf("%d\n",k-num*2+num);}}

总结:t1日常被卡,我真的是个妖怪,要注意别想太复杂了,毕竟是t1,然后只要t1半小时内写完,后面就有时间打个对拍,应该就会很稳了。

原创粉丝点击