2015.08.08总结

来源:互联网 发布:动力学仿真软件ls 编辑:程序博客网 时间:2024/06/05 20:36

NOIP2015提高组模拟8.8

P1 3476. 【NOIP2013初赛】整除

这题其实是一道货真价实的水题,正解就是DFS+容斥原理。先DFS枚举若干个数的Lcm再根据容斥原理计算,可得出答案。顺便,可以将题目转化为求[1~R]-[1~L-1],便于处理。

P2 3473. 铺砖问题

嘛。。。经典问题,就个人感觉来说,这道题是这套题中最难的一道。正解是矩阵优化+快速幂。50分的状压DP(设F[i][j]表示做完前i列),可以预处理出转移的状态,便于后面的转移。另外的50分用矩阵乘法+快速幂来处理,还是先DFS预处理一个矩阵Mat,Mat[i][j]=1表示压缩后的状态可以转移到j,再求该矩阵的n次幂,最后答案就是Mat[0][0].
SRC:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define N 100+10#define M 2500+10typedef long long ll;const int Mo=1000000007;struct Matrixtype {    int mat[N][N];}a,b,tmp,ma;int n[210];int jl[M][M],f[2][M];char s[210];int m,maxn,ans;void Pre(int st,int k,int num) {    if(k>=m) {        jl[st][++jl[st][0]]=num;        return;    }    if((1 << k) & st) {Pre(st,k+1,num); return;}    Pre(st,k+1,num+(1 << k));    if(k+1<m && !((1 << (k+1)) & st)) Pre(st,k+2,num);}void Make(int st,int k,int num) {    if(k>=m) {        ma.mat[st][num]=1;        return;    }    if((1 << k) & st) {Make(st,k+1,num); return;}    Make(st,k+1,num+(1 << k));    if(k+1<m && !((1 << (k+1)) & st)) Make(st,k+2,num);}int Div() {    int r=0;    for(int i=n[0];i>0;i--) {        n[i]+=r*10;        r=n[i]%2;        n[i]/=2;    }    if(!n[n[0]]) n[0]--;    return r;}Matrixtype mult(Matrixtype a,Matrixtype b) {    Matrixtype c;    memset(c.mat,0,sizeof(c.mat));    for(int i=0;i<=maxn;i++) {        for(int j=0;j<=maxn;j++) {            for(int k=0;k<=maxn;k++) {                c.mat[i][j]=(c.mat[i][j]+(ll)a.mat[i][k]*b.mat[k][j])%Mo;            }        }    }    return c;}void Quickmi() {    for(int i=0;i<=maxn;i++) tmp.mat[i][i]=1;    while(n[0]) {        int rest=Div();        if(rest) tmp=mult(tmp,ma);        ma=mult(ma,ma);    }}int main(){    freopen("p2.in","r",stdin);    freopen("p2.out","w",stdout);    scanf("%s%d",s,&m);    int len=strlen(s);    maxn=(1 << m) - 1 ;    if(m>5) {        f[0][0]=1;        int nn=0,now=0;        for(int i=0;i<len;i++) nn=nn*10+s[i]-'0';        for(int i=0;i<=maxn;i++) Pre(i,0,0);        for(int i=0;i<nn;i++) {            for(int j=0;j<=maxn;j++) {                if(!f[now][j]) continue;                for(int k=1;k<=jl[j][0];k++) {                    f[~now][jl[j][k]]=(f[~now][jl[j][k]]+f[now][j])%Mo;                }            }            memset(f[now],0,sizeof(f[now]));            now=~now;        }        ans=f[now][0];    } else {        n[0]=len;        for(int i=0;i<len;i++)        {            if(i==len-1) {                i++;                i--;                i++;                i--;            }            n[len-i]=s[i]-'0';        }        for(int i=0;i<=maxn;i++)            Make(i,0,0);        Quickmi();        ans=tmp.mat[0][0];    }    printf("%d\n",ans);}

P3 3475. 【NOIP2012初赛】新壳栈

初赛原题,这题可以维护一个双向队列和一个栈,对于栈顶的c个元素,我们放入队列中,其余元素放在栈中。对于翻转操作只需要O(1)交换队头和队尾指针即可。但不知为什么,用C++的reverse()跑的特别快,因此诞生了一种水法。
水法:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define N 1000000+10int q[N];int c,k,top;int main(){    scanf("%d",&c);    scanf("%d",&k);    while(k!=0) {        if(k==1) {            int e;            scanf("%d",&e);            q[++top]=e;        }        if(k==2) {            if(top<1) printf("Error: the stack is empty!\n");            else printf("%d\n",q[top]),top--;        }        if(k==3) {            if(top<c) printf("Error: less than %d elements in the stack!\n",c);            else reverse(q+1+top-c,q+1+top);        }        scanf("%d",&k);    }    return 0;}

P4 【NOIP2013初赛】青蛙

我们设F[i]表示n=i的答案。易得F[i]=(F[1]+F[2]+…+F[i])/n+1
化简得F[i]=(F[1]+F[2]+…+F[i-1]+i)/(n-1)

SRC:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define N 20000+10double f[N],s[N];int n;int main(){    scanf("%d",&n);    for(int i=2;i<=n;i++) f[i]=(s[i-1]+i)/(i-1),s[i]=f[i]+s[i-1];    printf("%.2f\n",f[n]);    return 0;}

以上.

0 0