2018.8.10提高B组模拟考试

Posted water-radish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018.8.10提高B组模拟考试相关的知识,希望对你有一定的参考价值。

为了迎合今天的讲课内容——数论,A组和B组都各出了两道数学。

对于完全不会数论的博主来说,这简直是灾难。

T1 题意简述:jzoj5791

   解题思路:看到这道题,首先想到对n个数分别分解成质数后存在数组里。

             然后呢?枚举ans吗?

             其实可以二分答案,加上一个求质数个数的技巧就能过。

             发现cnt[2]=ans/2+ans/4+ans/8+...

                 cnt[3]=ans/3+ans/9+ans/27+...

             本题结束。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
ll n,tot,ans=INF,pri[100001],prime[100001],cnt[100001];
void getpri()
{
    pri[1]=1;
    for(ll i=2;i<=100000;i++)
        if(!pri[i])
        {
            ll j=2;
            while(i*j<=100000)
                pri[i*j]=1,j++;
            prime[++prime[0]]=i;
        }
}
int main()
{
    freopen("factorial.in","r",stdin);
    freopen("factorial.out","w",stdout);
    scanf("%lld",&n);
    getpri();
    for(ll i=1;i<=n;i++)
    {
        ll u;
        scanf("%lld",&u);
        for(ll i=1;i<=prime[0];i++)
        {
            if(u==1) break;
            if(!pri[u]) {cnt[u]++,tot++;break;}
            if(!(u%prime[i])) while(!(u%prime[i])) u/=prime[i],cnt[prime[i]]++,tot++;
        }
    }
    ll l=1,r=5000000;
    while(l<r)
    {
        ll mid=(l+r)>>1,flag=1;
        for(ll i=1;i<=prime[0];i++)
        {
            ll tmp=1,num=0;
            while(tmp*prime[i]<=mid)
            {
                tmp*=prime[i];
                num+=mid/tmp;
            }
            if(num<cnt[prime[i]]) {flag=0;break;}
        }
        if(flag) r=mid,ans=min(ans,mid);
        else l=mid+1;
    }
    printf("%lld
",ans);
    return 0;
}

 


 

T2 题意简述:jzoj5793

   解题思路:首先本蒟蒻强烈谴责出题人!

技术分享图片

 

技术分享图片

             好吧其实出题人说的没错。

             这题的官方题解是BFS,其实dijkstra也可以水过。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#define INF 0x3f3f3f3f
using namespace std;
int n,m,ans=INF,a[501][501],step[250001][5],vis[250001][5];
char s[501];
queue<int> que,que1;
void bfs()
{
    que.push(1);que.push(1);
    que1.push(2);que1.push(4);
    vis[1][2]=vis[1][4]=1;
    step[1][2]=step[1][4]=0;
    while(!que.empty())
    {
        int now=que.front(),dir=que1.front();
        que.pop();que1.pop();
        vis[now][dir]=0;
        int x=now/m+1,y=now%m;
        if(!y) x--,y+=m;
        if(!a[x][y]) continue;
        if(a[x][y]!=1&&x!=1)
        {
            int old=step[now-m][1];
            if(dir!=1) step[now-m][1]=min(step[now-m][1],step[now][dir]+1);
            else step[now-m][1]=min(step[now-m][1],step[now][dir]);
            if(!vis[now-m][1]&&step[now-m][1]<old) vis[now-m][1]=1,que.push(now-m),que1.push(1);
        }
        if(a[x][y]!=2&&x!=n)
        {
            int old=step[now+m][2];
            if(dir!=2) step[now+m][2]=min(step[now+m][2],step[now][dir]+1);
            else step[now+m][2]=min(step[now+m][2],step[now][dir]);
            if(!vis[now+m][2]&&step[now+m][2]<old) vis[now+m][2]=1,que.push(now+m),que1.push(2);
        }
        if(a[x][y]!=3&&y!=1)
        {
            int old=step[now-1][3];
            if(dir!=3) step[now-1][3]=min(step[now-1][3],step[now][dir]+1);
            else step[now-1][3]=min(step[now-1][3],step[now][dir]);
            if(!vis[now-1][3]&&step[now-1][3]<old) vis[now-1][3]=1,que.push(now-1),que1.push(3);
        }
        if(a[x][y]!=4&&y!=m)
        {
            int old=step[now+1][4];
            if(dir!=4) step[now+1][4]=min(step[now+1][4],step[now][dir]+1);
            else step[now+1][4]=min(step[now+1][4],step[now][dir]);
            if(!vis[now+1][4]&&step[now+1][4]<old) vis[now+1][4]=1,que.push(now+1),que1.push(4);
        }
    }
}
int main()
{
    freopen("run.in","r",stdin);
    freopen("run.out","w",stdout);
    memset(step,0x3f,sizeof(step));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
        {
            if(s[j]==U) a[i][j]=1;
            if(s[j]==D) a[i][j]=2;
            if(s[j]==L) a[i][j]=3;
            if(s[j]==R) a[i][j]=4;
        }
    }
    bfs();
    for(int i=1;i<=4;i++)
        ans=min(ans,step[n*m][i]);
    if(ans==INF) printf("No Solution
");
    else printf("%d
",ans);
    return 0;
}

 


 

T3 题意简述:jzoj5787

   解题思路:首先本蒟蒻再次强烈谴责出题人!

技术分享图片

技术分享图片

技术分享图片

技术分享图片

技术分享图片

             然后他这几个问题ppt里都没给答案。

             我:???

             最重点的是在这五连询问后面跟了一句这个:

技术分享图片

技术分享图片

              好吧其实这题是这么做的。

             首先想到DP。(怎么想到的?我也不知道)

             设dp[i][j]记录枚举到第i个数,这i个数的乘积为j。

             发现数组根本开不下,考虑精简。

             发现对于乘积我们需要知道的只有它和k的最大公约数。

             因此修改dp[i][j]为枚举到第i个数,这i个数的乘积与k的最大公约数是k的第j个约数。

             现在咱们来解决他提出的第一个问题:为什么与k的最大公约数一定是k的约数呢?

             解答:这还用解决?这不是性质吗2333

             考虑转移。发现dp[i][j]=dp[i-1][k]*dp[1][a[j]/a[k]是k的第几个约数]。

             这里a[i]表示k的第i个小于等于m的约数,以后的a[i]也相同。

             现在咱们来解决他提出的第二个问题:为什么a[j]/a[k]一定是k的约数呢?

             解答:参见第一问解答。(2333)

             考虑求出dp[1][1~k的约数个数]。发现答案即为在1~m中与k的最大公约数是a[i]的个数。

             设这个问题为问题x,那么可以先枚举1~m,再枚举a[i]即可。

             现在咱们来解决他提出的第三个问题:问题x的原理是什么呢?

             解答:...如果您不知道,请阅读上文中dp[i][j]的定义。

             发现这个求dp[1][i]的方法的速度太慢,只能过40%的点。考虑优化。

             然后这里就是精髓了。出题人想到了容斥,但是却没有给出问题四的答案。

             又因为本博主太蒟,没能想到容斥系数。

             所以这篇博客暂时就到这里了。关于之后的部分本蒟会和身边的各位大佬研究后再放出来。

以上是关于2018.8.10提高B组模拟考试的主要内容,如果未能解决你的问题,请参考以下文章

2018.8.9提高B组模拟考试

2018.8.6提高A组模拟考试

2021.7.21提高B组模拟8T1 好数(模拟)

2021.8.13提高B组模拟5T1 Brothers(暴力)

2021.8.10提高B组模拟2T1 单峰(快速幂)

2021.8.10提高B组模拟2T1 单峰(快速幂)