2018.8.21提高A&省选组模拟考试

为什么8月份的考试拖到现在才发题解呢?

因为实际上这是我们昨天才考的...只不过正好和某校8月份的模拟考试重题而已...

 

T1 题意简述:jzoj5835

 

Description

Input

Output

Data Constraint

 

   解题思路:很简单的一道筛法题。

             分析题目,发现只需要筛出[1,min(K,sqrt(R))]范围内的质数即可。

#include<algorithm>//STL通用算法
#include<bitset>//STL位集容器
#include<cctype>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>//STL双端队列容器
#include<list>//STL线性列表容器
#include<map>//STL映射容器
#include<iostream>
#include<queue>//STL队列容器
#include<set>//STL集合容器
#include<stack>//STL堆栈容器
#include<utility>//STL通用模板类
#include<vector>//STL动态数组容器
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
ll L,R,n,len,ans,sch[10000005];
ll cnt,pri[10000005],jdg[10000005];
void getpri()
{
    jdg[1]=1;
    for(ll i=2;i<=n;i++)
    {
        if(!jdg[i]) pri[++cnt]=i;
        for(ll j=1;j<=cnt;j++)
        {
            if(pri[j]*i>n) break;
            jdg[i*pri[j]]=1;
            if(!(i%pri[j])) break;
        }
    }
}
int main()
{
    freopen("prime.in","r",stdin);
    freopen("prime.out","w",stdout);
    scanf("%lld%lld%lld",&L,&R,&n);
    n=min((ll)sqrt(R),n),len=R-L+1;
    getpri();
    for(ll i=1;i<=cnt;i++)
    {
        ll tmp=(L/pri[i]+(L%pri[i]!=0))*pri[i]-L+1;
        while(tmp<=len) sch[tmp]=1,tmp+=pri[i];
        if(pri[i]>=L) sch[pri[i]-L+1]=0;
    }
    for(ll i=1;i<=len;i++) if(!sch[i]) ans^=L+i-1;
    printf("%lld\n",ans);
    return 0;
}

 


 

T2 题意简述:jzoj5836

 

Description

Input

Output

 

Data Constraint

 

   解题思路:贪心+矩阵乘法。

             首先考虑如何计算一个序列中的子序列个数。(子序列个数指互不重复的子序列个数。以下同理)

             题解中所给的式子是dp[num[i]]=∑(j=1,k)dp[j],其中dp[i]表示以i结尾的子序列个数。

             其实有一种式子更易理解:dp[i]=dp[i-1]*2-dp[pos[num[i]]-1](pos[i]!=0)。

             其中dp[i]表示序列第i项的子序列个数,pos[i]表示数字i在序列中上一次出现的位置。

             这个式子的意思是,在上一项的每个子序列后面都填上一个num[i],但是还要减去重复的。

             重复的子序列其实就是上次此数字出现时已经计入的子序列。当然,若还未出现过就不必减去了。

             用这个方法可以算出整个序列的子序列个数。

             接下来考虑m个待填数字。

             观察式子,发现要使结果最大,只需使dp[pos[num]-1]最小即可。

             易知,dp数组是单调递增的。因此,只需保证pos[num]-1最小便可保证结果最大。

             也就是说,每次取最早出现的那个元素作为当前项即可。

             直接递推复杂度O(n+m),这样的复杂度是无法接受的。考虑优化。

             众所周知,递推式可以用矩阵乘法优化。最终复杂度O(n+k+k^3logm)。

             为什么会有个(+k)?因为一开始的k项是无法用矩阵乘法优化的。

             pos在一开始的k项取值范围为[0,n],显然我们无法建一个n*n的矩阵。

             但是在经历一个循环节后,pos的取值范围就变成了[n+1,n+k],因此只需建一个(k+1)*(k+1)的矩阵即可。

#include<algorithm>//STL通用算法
#include<bitset>//STL位集容器
#include<cctype>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>//STL双端队列容器
#include<list>//STL线性列表容器
#include<map>//STL映射容器
#include<iostream>
#include<queue>//STL队列容器
#include<set>//STL集合容器
#include<stack>//STL堆栈容器
#include<utility>//STL通用模板类
#include<vector>//STL动态数组容器
#define INF 0x3f3f3f3f
#define ll long long
#define MOD 1000000007
using namespace std;
ll n,m,k,ans,num[1000010],pos[110],que[110],dp[2000010];
struct uio{
    ll pos,num;
}srt[110];
struct oiu{
    ll sqr[110][110];
    oiu(){memset(sqr,0,sizeof(sqr));}
    friend oiu operator *(const oiu &x,const oiu &y)
    {
        oiu z;
        for(ll i=1;i<=k+1;i++)
            for(ll j=1;j<=k+1;j++)
                for(ll l=1;l<=k+1;l++)
                    (z.sqr[i][j]+=x.sqr[i][l]*y.sqr[l][j]%MOD)%=MOD;
        return z;
    }
}mat,bgn;
bool cmp(uio x,uio y){return x.pos<y.pos;}
void init(oiu &x) {for(ll i=1;i<=k+1;i++) x.sqr[i][i]=1;}
oiu qpow(oiu x,ll y)
{
    oiu z;init(z);
    while(y) 
    {if(y&1) z=z*x;x=x*x;y/=2;}
    return z;
}
signed main()
{
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&k);
    for(ll i=1;i<=n;i++) scanf("%lld",&num[i]);
    dp[0]=1;
    for(ll i=1;i<=n;i++)
    {
        if(pos[num[i]]) dp[i]=(dp[i-1]*2-dp[pos[num[i]]-1]+MOD)%MOD;
        else dp[i]=dp[i-1]*2%MOD;
        pos[num[i]]=i;
    }
    for(ll i=1;i<=k;i++) srt[i]={pos[i],i};
    sort(srt+1,srt+1+k,cmp);
    for(ll i=1;i<=k;i++) que[i]=srt[i].num;
    for(ll i=n+1;i<=n+min(m,k);i++)
    {
        ll x=que[i-n];
        if(pos[x]) dp[i]=(dp[i-1]*2-dp[pos[x]-1]+MOD)%MOD;
        else dp[i]=dp[i-1]*2%MOD;
        pos[x]=i;
    }
    m-=k;if(m<=0) {printf("%lld\n",dp[n+m+k]-1);return 0;}
    mat.sqr[1][1]=2,mat.sqr[k+1][1]=-1;
    for(ll i=1;i<=k;i++) mat.sqr[i][i+1]=1;
    for(ll i=1;i<=k+1;i++) bgn.sqr[1][i]=dp[n+k-i+1];
    mat=qpow(mat,m);
    for(ll i=1;i<=k+1;i++) (ans+=bgn.sqr[1][i]*mat.sqr[i][1]%MOD+MOD)%=MOD;
    printf("%lld\n",(ans-1+MOD)%MOD);
    return 0;
}

 


 

T3 题意简述:jzoj5837

 

Description

Input

Output

Data Constraint

 

   解题思路:不会。博主看了题解后还是没写出来。

             在这里贴一个官方题解,有兴趣的大佬可了解一下。

posted @ 2018-10-19 21:24  radishえらい  阅读(112)  评论(0编辑  收藏  举报