【loli的胡策】NOIP训练8.10(数论+树形dp+贪心)

18 篇文章 0 订阅

这里写图片描述
题解:
贝祖定理:若设a,b是整数,则存在整数x,y,使得ax+by=gcd(a,b),那么我们可以知道如果 c不是gcd(m,n)的倍数,那么一定不是好的(虽然与我的算法无关,但还是说一下)
好了其实我的算法是—-暴力
代码:

#include <cstdio>
#include <cmath>
#include <iostream>
#define LL long long 
using namespace std;
int n,m;LL q;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main()
{
    int T,i,j;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%lld",&n,&m,&q);
        LL ans=q;
        if (n>m) swap(n,m);
        int minn=n,maxx=m;
        int gg=gcd(maxx,minn);
        n/=gg; m/=gg; q/=gg; 
        ans-=q/m+q/n-q/(n*m);
        for (i=1;i<minn;i++) 
          if (q<i*m) break;
          else ans-=(q-i*m)/n-(q-i*m)/(m*n);
        printf("%lld\n",ans);
    }
}

这里写图片描述
题解:
考场30pts暴力
这道题可以考虑枚举最大公因数,然后求最大公因数为i的最长链。我们考虑将每条边拆成因数条边,要是一次性加入的话数量会炸飞,所以我们每次将是当前公因数倍数的边加入,然后求树上的最长链,然后用当前的公因数更新长度为最长链的长度的答案。求解后将数组清0,重复利用有些长度不可能出现在最长链中,因为他是构成最长链的一部分,所以如果这个长度的答案<长度大于它的答案的话,就要将长度大于他的答案给他,从大到小枚举ans[i]=max(ans[i],ans[i+1]);
代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#define N 800005
#define Q 2000005
using namespace std;
int cnt,tot,nxtt[N],head[Q],x[N],y[N],nxt[N],point[N],v[N],sz,dian[N],d,vis[N],len,a[N];
void addquan(int z,int xx,int yy)
{
    ++cnt; nxtt[cnt]=head[z]; head[z]=cnt; x[cnt]=xx; y[cnt]=yy;
}
void addline(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
    dian[++d]=x; dian[++d]=y;
}
int dfs(int x,int fa)
{
    vis[x]=sz;
    int m1,m2; m1=m2=0;
    for (int i=point[x];i;i=nxt[i])
      if (v[i]!=fa)
      {
        int l=dfs(v[i],x);
        if (l+1>m1) m2=m1,m1=l+1;
        else m2=max(m2,l+1);
      }
    len=max(m1+m2,len);
    return m1;
}
int main()
{
    freopen("walk.in","r",stdin);
    freopen("walk.out","w",stdout);
    int n,i,j,ys;
    scanf("%d",&n);
    for (i=1;i<n;i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        addquan(c,a,b);
    }
    for (ys=1;ys<=100000;ys++)//枚举公因数 
    {
        for (j=ys;j<=100000;j+=ys)
          for (i=head[j];i;i=nxtt[i])
            addline(x[i],y[i]);
        ++sz;len=0;
        for (i=1;i<=d;i++)
          if (vis[dian[i]]!=sz) dfs(dian[i],0);
        a[len]=ys;
        d=0;tot=0;memset(point,0,sizeof(point));
    }
    for (i=n;i>=1;i--) a[i]=max(a[i],a[i+1]);  
    for (i=1;i<=n;i++)
      printf("%d\n",a[i]);
}

这里写图片描述
这里写图片描述
题解:挖坑待填

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值