2016.8.3测试解题报告(count,length,party)

关于这套题:
这套试题在第一次考的时候我并没有在教室里面而是由于一些意外离队了=。=补考之后再写题解感觉状态并不是很好…

1.数数

这是本套试题的第一题,水题。大概题意就是给出三个数n,m,k,并给出你n个数字a[i],让你验证a[i]中有几个数字的m次幂可以被k整除。考试的时候我想到了两种解法:

——解法1:
先将给出的目标数k分解质因数并记入kbook记录质数序号及次幂;然后依次分解给出的待验证的数字a[i],将分解出的book的值全都乘以m;最后,验证是否是k的倍数既是否book中的每一个值都大于kbook中的值,并统计答案。
考试的时候写的就是这个所以贴一波代码:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
bool prime(int k)
{
    if(k==1) return false;
    for(int i=2;i<=sqrt(k);i++) if(k%i==0) return false;
    return true;
}
int n,m,k;
int pri[1500];
int a[10005];
int kbook[1550];
int book[1550];
int ans=0;
int main()
{
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int cnt=0;
    for(int i=1;i<=10000;i++) if(prime(i)) {pri[++cnt]=i;}
    int kpos=1;
    while(k>1)
    {
        while(k%pri[kpos]==0) {k/=pri[kpos]; kbook[kpos]++;}
        kpos++;
    }
    int ccnt=0;
    for(int i=1;i<=n;i++)
    {
        memset(book,0,sizeof(book));
        int pos=1;
        int x=a[i];
        while(x>1)
        {
            while(x%pri[pos]==0) {x/=pri[pos]; book[pos]++;}
            pos++;
        }
        for(int j=1;j<=pos;j++) book[j]*=m;
        bool flag=1;
        for(int j=1;j<=kpos;j++) if(book[j]<kbook[j]) {flag=0; break;}
        if(flag) ans++;
    }
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

——解法2:
利用快速幂,快速幂每运算一遍都进行一步取余操作,当某一次运算的余数为0时,则此数的m次幂一定是k的倍数,时间复杂度和空间复杂度都优于第一种解法,而且比第一种写法更好实现,考试的时候没写,有时间了再贴代码。

2.最长链

题意:给定一个有n个结点的树,求出每个点到其他顶点的最大距离。

第二道题显然是此次测试中难度较大的一道题了。一开始我写了一个树剖+LCA以达到O(1)时间求每个点到其他点的路径长度,自己出了一个很弱的数据就把自己T了但是仍然没有时间再做修改于是考试的时候就侥幸水了40分。后来考完试一想马上就码了一发正解(早知道就不着急多想一会儿再写了),思路大概就是这样的。

先从根到叶走一遍dfs,dfs回溯的时候记录以下信息:最长子链长度,次长子链长度,最长子链顶点,次长子链顶点。然后每个点都dp一下,如果这个点在最长链上,先试着用该条最长链的长度到根的距离与该点到该祖先的距离做差更新答案,再试着用次长链长度与该点到其祖先顶点的距离的和更新答案;如果这个点不在最长链上,就用该点到某祖先的距离加上此祖先对应的最长链的长度更新答案。从叶节点开始递推到根节点,时间复杂度是不严格的O(nlogn),因为这种做法很容易被一条长链形的数据卡掉(所以显然此题数据很弱),对此可以进行的改进就是,rand() mod n一个根节点进行建树(技巧)

这道题我就不贴代码了,实在是懒得调,,,

3.聚会

题意:给出一个有向图,并给出一点k,输出每个点到点k的距离与k点到该点的路权和的最大值。

这题简直不能再裸……(但是具体坑人的地方在于各种特殊情况的处理!)这道题数据中出现过的特殊情况有:自环、平行边、环。考试的时候我考虑到了自环、环和复权回路的情况,但是万万没想到的就是还有一种特殊情况叫做平行边!(此处特别注意下次图论特别注意)于是乎我就写了一个多半情况下上称得上万能的SPFA+邻接表优化,一波就干掉了各种回路各种环。爆了一个点,改改就过了。

代码实现如下:

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
int maxx(int a,int b) {if(a>b) return a; return b;}
struct Edge
{
    int from,to,next;
    int val;
}eage[100005];
int n,m,k;
int head[1005];
int tot=0;
int dis[1005];
int que[50005];
bool book[1005];
int top=0;
int tail=0;
int f[1005];
int f1[1005];
void Insert(int x,int y,int z)
{
    eage[++tot].from=x;
    eage[tot].to=y;
    eage[tot].val=z;
    eage[tot].next=head[x];
    head[x]=tot;
}
void print()
{
    for(int i=1;i<=n;i++) cout<<dis[i]<<" ";
    cout<<endl;
}
int SPFA(int pos)
{
    for(int i=1;i<=n;i++) dis[i]=999999;
    dis[pos]=0;
    for(int i=head[pos];i;i=eage[i].next)
    {
        if(dis[eage[i].to]>dis[pos]+eage[i].val)
        {
            dis[eage[i].to]=dis[pos]+eage[i].val;
            if(!book[eage[i].to])
            {
                que[++tail]=eage[i].to;
                book[eage[i].to]=1;
            }
        }
    }
    while(top<tail)
    {
        top++;
        book[que[top]]=0;
        for(int i=head[que[top]];i;i=eage[i].next)
        {
            if(dis[eage[i].to]>dis[que[top]]+eage[i].val)
            {
                dis[eage[i].to]=dis[que[top]]+eage[i].val;
                if(!book[eage[i].to])
                {
                    que[++tail]=eage[i].to;
                    book[eage[i].to]=1;
                }
            }
        }
    }
    return dis[k];
}
int main()
{
    freopen("party.in","r",stdin);
    freopen("party.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        Insert(x,y,z);
    }
    for(int pos=1;pos<=n;pos++)
    {
        f[pos]=SPFA(pos);
        top=0;
        tail=0;
        memset(que,0,sizeof que);
        memset(book,0,sizeof book);
        memset(dis,0,sizeof dis);
    }
    //-------------------------------------------------------
    top=0;
    tail=0;
    memset(que,0,sizeof que);
    memset(book,0,sizeof book);
    memset(dis,0,sizeof dis);
    for(int i=1;i<=n;i++) dis[i]=999999;
    dis[k]=0;
    for(int i=head[k];i;i=eage[i].next)
    {
        if(dis[eage[i].to]>dis[k]+eage[i].val)
        {
            dis[eage[i].to]=dis[k]+eage[i].val;
            if(!book[eage[i].to])
            {
                que[++tail]=eage[i].to;
                book[eage[i].to]=1;
            }
        }
    }
    while(top<tail)
    {
        top++;
        book[que[top]]=0;
        for(int i=head[que[top]];i;i=eage[i].next)
        {
            if(dis[eage[i].to]>dis[que[top]]+eage[i].val)
            {
                dis[eage[i].to]=dis[que[top]]+eage[i].val;
                if(!book[eage[i].to])
                {
                    que[++tail]=eage[i].to;
                    book[eage[i].to]=1;
                }
            }
        }
    }
    for(int i=1;i<=n;i++) f1[i]=dis[i];
    int ans=0;
    for(int i=1;i<=n;i++) ans=maxx(ans,f[i]+f1[i]);
    printf("%d",ans);

    fclose(stdin);
    fclose(stdout);
    return 0;
}

·
关于此套试题,我总结出了一些经验教训:

  1. 代码写的工整清晰一点,有利于改错调试。
  2. 想清楚,想完善了之后在考虑代码实现,有时候正确的实现出来的不一定就是正确的思路。
  3. short int这种不太熟悉的东西不要乱用。
  4. next是系统关键字!!!
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值