2016.8.29 LGTB解题报告

考试总结:

1.这道题还是花了不少的时间的,特别是对拍啊之类的,总是放不下,然后有一些实现的问题导致改错也改了很久;

    解决方案:下一次在决定写程序的时候,一定要先在草稿纸上把实现算法的流程基本上写一次,精确到循环语句,判断语句的框架,把所有的情况都完整地考虑一次,确定没有问题了再写;

    这道题犯了和上一套第二题同样的问题:证明的时间过长;

解决方案:在解题时把流程规范化,在证明了算法正确性以后就放下了,不要总是把它提出来!

2.这道题的数据范围特别小,所以可以很容易地想到状压DP,然后考虑到互质的概念,就基本可以确定用位运算来表示质因数了,但是如果100个数考虑到极值100个数都变成质数的话,状压肯定是longlong存不下的,而NOIP难度很少考到比longlong范围大的状压,所以我最后只写了40分的程序,并且由于是第一次写状压,所以很荣幸地没调试出来,所以新学的知识点还是要做那么一两道题的,一是为了熟悉知识点与算法本质,二也是为了在考场上不至于那么害怕;然后正解分析了a<=30这个特性之后得出最多取到58,所以这说明,选定了一个算法之后就要去规范化地解决问题,比如边界比如初始化,而不是还盯着那个算法不知道干什么,专注于一个方面才能把这个方面做好

3.看题;

4.总结得出,我是那种只要文件和输入输出名没问题,没注销,仔细读了题就稳前3的人,当然,我这些方面经常出问题,所以一定要改;

解题报告:

一.LGTB与偶数:

题意:相邻的数同为奇数可以删,同为偶数可以删;

分析:如果遇到可以消的,那么消了以后也不会有坏的影响,因为如果本来被消的两个数也可以和另一边的消除,那么这两个数被删掉后旁边的数凑在一起也可以被消,反之,则本来也不能被消,所以遇到可以消除的就消除,那么一个偶数被消除后留下的肯定是一个奇数,所以就是线性的算法了;

注意:在消的过程中可能出现消完的情况,这时之前的奇偶性已经没有用了,要特殊情况考虑;

代码:

#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

const int maxn=2e9;

int tmp,n,f,flg;

int main()

{

         freopen("even.in","r",stdin);

         freopen("even.out","w",stdout);

         scanf("%d",&n);f=1;

         scanf("%d",&tmp);if(tmp%2)flg=1;

         for(int i=2;i<=n;i++){

                   scanf("%d",&tmp);

                   if(!f){

                   if(tmp%2)flg=1;else flg=0;

                   f=1;

             }

                   else if(tmp%2){

                     if(flg){f--;flg=0;}

                     else {f++;flg=1;}

                      }

                  else{

          if(flg){f++;flg=0;}

                     else {f--;flg=1;}

                   }

    }

    printf("%d",f);

         return 0;

}

二.LGTB与序列:

       题意:求由给定序列变成互质序列的最小增减数;

       分析:a<=30的特性可以分析得出a最多取到58,58以内素数很少所以可以直接状压质因子,提取出影响因素;对于选择很多的情况,直接枚举每个情况要比搜索还要节约时间(得多),然后会发现还是会超时,这时候,我们的神器——打表就出现啦!对于一个固定不变的东西,打表是很好的选择,对于a>b,变成数时肯定a变的数大一点比较优,所以快排;;

程序:

#include<iostream>

#include<cstdio>

#include<cmath>

#include<cstring>

#include<algorithm>

using namespace std;

int f[80005][105],map[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};

int a[105];

int bit[59]={0,0,1,2,1,4,3,8,1,2,5,16,3,32,9,6,1,64,3,128,5,10,17,256,3,4,33,2,9,512,7,1024,1,18,65,12,3,2048,129,34,5,4096,11,8192,17,6,257,16384,3,8,5,66,33,32768,3,20,9,130,513};

int n;

const int maxn=1<<16;

bool cmp(int x,int y)

{

  if(x>y)return true;

  else return false;

}

int main()

{

  freopen("seq.in","r",stdin);

  freopen("seq.out","w",stdout);

  scanf("%d",&n);

  for(int i=1;i<=n;i++)scanf("%d",&a[i]);sort(a+1,a+n+1,cmp);

  memset(f,127,sizeof(f));

  for(int i=0;i<maxn;i++)f[i][0]=0;

  int mini=min(16,n);

  for(int i=1;i<=mini;i++)

    for(int j=0;j<maxn;j++)if(f[j][i-1]<2e9)

    for(int k=1;k<=58;k++)

  {

  if(bit[k]&j)continue;

  if(abs(a[i]-k)+f[j][i-1]<f[bit[k]|j][i])f[bit[k]|j][i]=abs(a[i]-k)+f[j][i-1];

  }

    int mini2=mini;mini=2e9;

    for(int i=1;i<maxn;i++)mini=min(mini,f[i][mini2]);

  for(int i=17;i<=n;i++)mini+=abs(a[i]-1);

  printf("%d",mini);

  return 0;

}

     

 

三.LGTB与大数

题意:对一个字符串经行处理,每次把一个数字替换为一个数字串,最火输出这个数字串对1e9+7取mod的结果;

分析:链表实现过了40分,存不下;正解是从后向前推每个数字最后变成了哪个数,这样可以确定排除这个数代表的数又被改了的问题,是一种操作的逆向化,这道题也要小心纪录转换成的数字串的长度可能会超范围,而长度的唯一作用就是用来快速幂,所以可以直接mod(运用费马小定理,注意1e9+7是质数!这是一条很重要的性质!(虽然没有很强的指向性))

程序:

#include<iostream>

#include<cstdio>

#include<cstring>

#include<string>

using namespace std;

long long ans,m[10][100005],ll[11];

long long len[100010],n;

string tov[100005],tmp;

char fr[100010],a[100005];

const int mod=1000000007;

/*int qpow(int u)

{

         u%=mod-1;int an=10;

         if(!u)return 1;u--;

         while(u){

                   if(u&1)an*=10;

                   if(u!=1)an*=an;

                   an%=mod;

                   u>>=1;

    }

    return an;

}*/

long long qpow(long long b)

{

    b%=mod-1;long long an=10;

         long long ss=1;

    while(b)

    {

        if(b&1) ss=ss*an,ss%=mod;

        an*=an,an%=mod;

        b>>=1;

    }

    return ss;

}

int main()

{

         freopen("number.in","r",stdin);

         freopen("number.out","w",stdout);

         scanf("%s",a);scanf("%I64d",&n);

         for(int i=1;i<=n;i++){

                   getchar();

                   cin>>tmp;//cout<<tmp;

                   fr[i]=tmp[0];

                   len[i]=tmp.size()-3;

                   tov[i]=tmp.substr(3,len[i]);

         }

         for(int i=0;i<=9;i++){

         m[i][n+1]=i;ll[i]=1;}

         for(int i=n;i>=1;i--)for(int k=0;k<=9;k++)if(k==fr[i]-'0'){             

         long long tot=0;

         for(int j=0;j<len[i];j++)if(ll[tov[i][j]-'0']){

                   int ns=tov[i][j]-'0';

         m[k][i]*=qpow(ll[tov[i][j]-'0']);m[k][i]%=mod;

         m[k][i]+=m[tov[i][j]-'0'][i+1];m[k][i]%=mod;

         tot+=ll[tov[i][j]-'0'];tot%=mod-1;

         }

         ll[k]=tot;if(!ll[k])ll[k]=mod-1;

    }

    else{

             m[k][i]=m[k][i+1];

    }

         long long l=strlen(a);

         for(int i=0;i<l;i++){

    ans*=qpow(ll[a[i]-'0']);ans%=mod;

         ans+=m[a[i]-'0'][1]; ans%=mod;

         }

         printf("%I64d",ans%mod);

         return 0;

}

posted @ 2016-08-29 16:53  Sindar_CX  阅读(408)  评论(0编辑  收藏  举报