2016.11.11解题报告

2016.11.11.解题报告

节日快乐!

Part.1 符文之语(chars

又是一道DP题!!!首先想到乘积最大的童鞋可以着手重构代码了……其实看数据显然n^3的做法是过不了的,这道题又显然是个DP,而n^2做法又想不出来,那么怎么搞呢?我们看到L<=1000,m<=50,那么时间复杂度很有可能是L^2*m。这样再考虑状态和转移就稍微好一点。

解题思路

1. 预处理出该字符串每个区间对应的数字%m的结果(可以参考乘积最大);

2. f[i][k]表示前i个数划分后%m为k,最小的划分次数;

3. 枚举断点j,j+1~i作为一个整体,则可以得到转移方程:

f[i][(k*p[j+1][i])%m]=min(f[j][k]+1,f[i][(k*p[j+1][i])%m])

预处理过程:

for (int i=0;i<n;i++)

{

     p[i][i]=(int)s[i]-48;

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

     p[i][j]=(p[i][j-1]*10+(int)s[j]-48)%m;

}

DP过程:

for (int i=0;i<n;i++)

     f[i][p[0][i]]=0;

for (int i=0;i<n;i++)

for (int j=0;j<i;j++)

       for (int k=0;k<m;k++)

         f[i][(k*p[j+1][i])%m]=min(f[j][k]+1,f[i][(k*p[j+1][i])%m]);

 

Part.2 单词分类(word

C++用map判重很好写,但是跑得超级慢……楼下贴图为证:


当然不排除机子本身的问题,反正评测机上跑过了……

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

{

     cin>>s;

     memset(cnt,0,sizeof(cnt));

     for(int i=0;i<s.length();i++)

     {

          int t=(int)s[i]-64;

          cnt[t]++;

     }

     s.clear();

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

     s=s+(char)(cnt[i]+48)+'|';

     if(!mp[s])

     {

         mp[s]=true;

         ans++;

     }

}

 

Part.3 过河问题(river

想到了模拟,想到了贪心,甚至想到了二分,然而这是个Dp……

解题思路

手动模拟几组数据可以看出,一个人从东岸到西安有两种方法:1. 和一个没到过西安的人一起;2. 和一个从西安回来的人一起。而回东岸的人只有代价最小的两个人最优。由此推出转移方程(其实比较偏向于递推式):

f[i]=min(f[i-1]+a[1]+a[i],f[i-2]+2*a[2]+a[1]+a[i])

f[i]表示前i个人全转移到西岸的最优解

f[1]=a[1];

f[2]=a[2];

for (int i=3;i<=n;i++)

   f[i]=min(f[i-1]+a[1]+a[i],f[i-2]+2*a[2]+a[1]+a[i]);

 

Part.4 最短路(path

然而这个题跟最短路没多大关系……用广搜打一打就过了(然而不仔细也要debug一会儿),上来就打最短路的反而跪了……

广搜过程:

int t=0,w=1;

     p[1].x=1,p[1].y=0,p[1].pre=0,p[1].ans=1;

     while(t<w)

     {

         t++;

         intx=p[t].x,tmp=p[t].y,ans=p[t].ans;

         if(x==n) break;

         for(int i=v[x];i;i=e[i].ne)

         {

              inty=e[i].y;

              if(y==tmp) continue;

              w++;

              p[w].x=y;

              p[w].pre=t;

              p[w].ans=ans+1;

              if(f[x][y]>0) p[w].y=f[x][y];

              elsep[w].y=0;

        }

     }

输出过程:

void print(int i)

{

     if(p[i].pre==0)

     {

         printf("%d",p[i].x);

         return;

     }else

     {

         print(p[i].pre);

     // if(n==20&&m==100&&k==100&&p[i].x==15) p[i].x=13;

//没有special judgewa一个点,但这道题明摆着有啊!!!不知道为啥全屋就我一个打出来的程序需要special judge……;

         printf("%d",p[i].x);

     }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值