计蒜客D2 题解在这里!!!

发表在    手把手教你C++ 09-03 09:13:38

0 2102 4

以下解法全是我的弱鸡解法,请大神指点!!!

题目就不细读了


第一题

思路:用下标从0到10的数组来存,每个元素i表示i岁的兔子有几只

先说60分做法:纯纯的模拟!!!

循环n年,每年做这些事:

1.符合生育要求的兔子就生宝宝(注意,宝宝要放到a[0]里面,代表0岁)

2.每只兔子,出刚生下来的外,年龄增加!

3.到了10岁的兔子,就让a[10]=0,做清零处理


最后统计一共几只兔子

搞定!

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define MOD 1000000007
using namespace std;
int main()
{
  freopen("d2t1.in","r",stdin);
  freopen("d2t1.out","w",stdout);
  int num,ans=0;
  int rabit[11]={0};
  rabit[1]=1;
  scanf("%d",&num);
   for(int i=1;i<=num;i++)
   {
    for(int j=2;j<=10;j++)
        rabit[0]=(rabit[0]+rabit[j])%MOD;
    for(int j=10;j>=1;j--)
        rabit[j]=rabit[j-1];
    rabit[0]=0;
   }
  for(int i=1;i<=10;i++)
    ans=(ans+rabit[i])%MOD;
  printf("%d",ans);
  return 0;
  }




满分解法:矩阵乘法+快速幂

用二维来存兔子,然后矩阵乘法,对结果进行快速幂,即可求得结果

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int mod=1000000007;
using namespace std;
long long n,c[11][11]={
{1,0,0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,0,0,0,0,0,0},
{0,0,1,0,0,0,0,0,0,0,0},
{0,0,0,1,0,0,0,0,0,0,0},
{0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,1,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0},
{0,0,0,0,0,0,0,1,0,0,0},
{0,0,0,0,0,0,0,0,1,0,0},
{0,0,0,0,0,0,0,0,0,1,0},
{0,0,0,0,0,0,0,0,0,0,1}
};
long long b[11][11]={
{0,1,0,0,0,0,0,0,0,0,0},
{1,0,1,0,0,0,0,0,0,0,0},
{1,0,0,1,0,0,0,0,0,0,0},
{1,0,0,0,1,0,0,0,0,0,0},
{1,0,0,0,0,1,0,0,0,0,0},
{1,0,0,0,0,0,1,0,0,0,0},
{1,0,0,0,0,0,0,1,0,0,0},
{1,0,0,0,0,0,0,0,1,0,0},
{1,0,0,0,0,0,0,0,0,1,0},
{1,0,0,0,0,0,0,0,0,0,0},
{1,0,0,0,0,0,0,0,0,0,0}
};
long long ans;
struct mtx
{
  long long a[11][11];
  mtx()
  {
    for(long long i=0;i<=10;i++)
      for(long long j=0;j<=10;j++)
        a[i][j]=0;
  }
  mtx(long long b[11][11])
  {
    for(long long i=0;i<=10;i++)
      for(long long j=0;j<=10;j++)
        a[i][j]=b[i][j];
  }
  mtx operator * (mtx b)
  {
    mtx ans;
    for(long long i=0;i<=10;i++)
      for(long long j=0;j<=10;j++)
        for(long long k=0;k<=10;k++)
          ans.a[i][j]=(ans.a[i][j]+(a[i][k]*b.a[k][j])%mod)%mod;
    return ans;
  }
}mtr_ans,mtr_spc;
int main()
{
  freopen("d2t1.in","r",stdin);
  freopen("d2t1.out","w",stdout);
  mtr_ans=mtx(c);mtr_spc=mtx(b);
  scanf("%lld",&n);
  while(n)
  {
    if(n&1)mtr_ans=mtr_ans*mtr_spc;
      mtr_spc=mtr_spc*mtr_spc;
    n>>=1;
  }
  for(long long i=0;i<=10;i++)
    ans=(ans+mtr_ans.a[0][i])%mod;
  printf("%lld\n",ans);
  return 0;
}



第二题:

60分做法:

对读入的数据进行处理,不用再开一个循环了,然后模拟冒泡排序(冒几次,统计几次),最后输出。

代码如下:(冒泡部分优化

#include<iostream>
#include<cmath>
using namespace std;
const int MAX=100001;
int main()
{
  freopen("d2t2.in","r",stdin);
  freopen("d2t2.out","w",stdout);
  int num;
  int a[MAX]={0};
  scanf("%d",&num);
  for(int i=1;i<=num;i++)
    scanf("%d",&a[i]);
  scanf("%d",&num);
  for(int n=1;n<=num;n++)
  {
    int begin,end;
	scanf("%d %d",&begin,&end);
	int b[MAX]={0},tum=1;
	for(int i=begin;i<=end;i++)
	{
	  b[tum++]=a[i];
	  }	  tum--;
	int ans=0;
	int i=1;
	bool flag;
	do
	{
	  flag=true;
	  for(int j=1;j<=tum-i;j++)
	    if(b[j]>b[j+1])
		{
		  int tmp;
		  tmp=b[j];
		  b[j]=b[j+1];
		  b[j+1]=tmp;
		  flag=false;
		  ans++;
		  }
	  i++;
	  }while(!flag);
	/*
	for(int i=1;i<=tum-1;i++)
	  for(int j=1;j<=tum-i;j++)
	  {
	    if(b[j]>b[j+1])
		{
		  int tmp;
		  tmp=b[j];
		  b[j]=b[j+1];
		  b[j+1]=tmp;
		  ans++;
		  }
		}*/
	printf("%d\n",ans);
	}
  return 0

}



满分解法:莫队+树状数组

思路:数学证明,可得出转移思路!!!

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long maxn=30000+10;
long long bit[maxn],ar[maxn],n,m;
long long lowbit(long long k){return k&-k;}
void update(long long k,long long a)
{
  while(k<=n)
  {
    bit[k]+=a;
    k+=lowbit(k);
  }
}
long long query(long long k)
{
  long long sum=0;
  while(k>0)
  {
    sum+=bit[k];
    k-=k&-k;
  }
  return sum;
}
int main()
{
  freopen("d2t2.in","r",stdin);
  freopen("d2t2.out","w",stdout);
  scanf("%lld",&n);
  for(long long i=1;i<=n;i++)
    scanf("%lld",&ar[i]);
  memset(bit,0,sizeof(bit));
  scanf("%lld",&m);
  long long sum=0;
  long long lp=1,rp=1;
  update(ar[1],1);
  for(long long i=1;i<=m;i++)
  {
    long long l,r;
    scanf("%lld%lld",&l,&r);
    while(lp<l)
    {
      update(ar[lp],-1);
      sum-=query(ar[lp]-1);
      lp++;
    }
    while(lp>l)
    {
      lp--;
      sum+=query(ar[lp]-1);
      update(ar[lp],1);
    }
    while(rp<r)
    {
      rp++;
      sum+=query(n)-query(ar[rp]);
      update(ar[rp],1);
    }
    while(rp>r)
    {
      update(ar[rp],-1);
      sum-=query(n)-query(ar[rp]);
      rp--;
    }
    printf("%lld\n",sum);
  }
  return 0;
}





第三题:

——用三进制表示村民状态

先看数据:

救一个人得10分,不要白不要!!!

用搜索得20,代码就不讲了


60分解法:广搜

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,m,k,map[11][11],tim[11],num=0;
struct data
{
	int x,y,step;
}h[11],s,t;
char a[11];

int bfs(data from,data to,int v)
{
  queue<data> q;
  bool vis[11][11]={{0},{0}};
  int mx[5]={0},my[5]={0};
  mx[1]=1;
  mx[2]=-1;
  my[3]=1;
  my[4]=-1;
  from.step=0;
  vis[from.x][from.y]=1;
  q.push(from);
  while(!q.empty())
  {
    data u=q.front();
    q.pop();
    if(u.x==to.x&&u.y==to.y)
    {
      if(v>1)
        return u.step*v;
      else
        return u.step;
    }
    for(int i=1;i<=4;i++)
    {
      data g=u;
      g.step++;
      g.x+=mx[i];
      g.y+=my[i];
      if(g.x<1||g.x>n||g.y<1||g.y>n)
        continue;
      if(map[g.x][g.y])
        continue;
      if(vis[g.x][g.y])
        continue;
      q.push(g);
    }
  }
  return 0;
}

int main()
{
  freopen("d2t3.in","r",stdin);
  freopen("d2t3.out","w",stdout);
  scanf("%d%d%d",&n,&m,&k);
  for(int i=1;i<=n;i++)
  {
    scanf("%s",a);
    for(int j=0;j<m;j++)
    {
      if(a[j]=='.') continue;
      if(a[j]=='#')
      {
        map[i][j+1]=1;
        continue;
      }
      if(a[j]=='s')
      {
        s.x=i;
        s.y=j+1;
        continue;
      }
      if(a[j]=='t')
      {
        t.x=i;
        t.y=j+1;
        continue;
      }
      if(a[j]>='A'&&a[j]<='Z')
      {
        num++;
        h[a[j]-'A'+1].x=i;
        h[a[j]-'A'+1].y=j+1;
        continue;
      }
    }
  }
  for(int i=1;i<=num;i++)
  {
    int temp;
    scanf("%s%d",a,&temp);
    tim[a[0]-'A'+1]=temp;
  }
  int odr[11],mint=9999999;
  for(int i=1;i<=n;i++)
    odr[i]=i;
  do
  {
    int ans=0,v=k;
    ans+=bfs(s,h[odr[1]],v);
    if(ans>mint)
      continue;
    v=v+tim[odr[1]];
    for(int i=1;i<num;i++)
    {
      ans+=bfs(h[odr[i]],h[odr[i+1]],v);
      v=v+tim[odr[i+1]];
      if(ans>mint)
        continue;
    }
    ans+=bfs(h[odr[num]],t,v);
    mint=min(mint,ans);
  }while(next_permutation(odr+1,odr+1+num));
  printf("%d",mint);
  return 0;
}


满分解法:

听说用dp,但是,还是小白的我,只会对付高中生的dp啊!!!

所以,代码木有,不会写,想看的可以上网搜!!!


嘿嘿柯的分数是260分,有没有大神超过了呢?

有点话,请在评论区自豪地发言!!!




怎么样,简单吧,轻轻松松上200分!!!

有异议的在评论区留言哦~


登录或注册后发布评论