百度之星资格赛

1001

给你1~n这n个数字,升序排列,接下来按照数组a进行位置变换,a[i]代表第i个数字会变到a[i]位置上,a中的数字也是从1~n。现在问有多少个不同的数组能满足做一次变换和做三次变换结果相同。


我们可以这样分析,x->y是唯一的到y的途径,假设x->y为第一次变换,因此在第三次变换的时候任然为x->y,第二次变换的初始点为y,而第三次变换的初始点为x,因此第二次变换为y->x,因此,对于数组a,只要有任意两个数字互相交换位置即是一种合法的情况。接下来就是计算n个数字有多少种情况。

我们可以发现这个问题具有子结构,因此考虑到dp来解,假设dp[i]为长度为i的数组的合法情况,那么当长度为i+1时dp[i+1] = dp[i] + i * dp[i - 1],其含义就是,我可以把多出来的这个元素单独放在一边,那么就有1*dp[i]种,或者与前面的任意一个元素互换,那么就有i*dp[i-1]。然后只需要进行一下预处理就可以了,dp[0] = 0,dp[1] = 1。复杂度为o(n)。

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

#define mod 1000000007
#define M 1000100
#define LL long long
LL dp[M];

void init(){
     memset(dp,0,sizeof(dp));
     dp[0] = 1;
     dp[1] = 1;
     for(int i = 2;i < M;i++){
        dp[i] = dp[i-1] + (dp[i-2]*(LL)(i-1))%mod;
        dp[i] %= mod;
     }
}


int main(){
    init();
    int T;
    cin>>T;
    int cas = 1;
    init();
    while(T--){
        int n;
        cin>>n;
        cout<<"Case #"<<cas++<<":"<<endl;
        cout<<dp[n]<<endl;
    }
    return 0;
}

1003

这个题就是用map,用map来离散化非常方便。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
#define N 1010
map<int,bool>M;
int ip[N],mac[100];

void read(int z[],int i){
    int a,b,c,d;
    scanf("%d.%d.%d.%d",&a,&b,&c,&d);
    z[i] = 0;
    z[i] += a<<24;
    z[i] += b<<16;
    z[i] += c<<8;
    z[i] += d;
}


int main(){
    int T;
    scanf("%d",&T);
    int cas = 1;
    while(T--){
        printf("Case #%d:\n",cas++);
        int n,m,a,b,c,d;
        map<int,bool>::iterator it;
        scanf("%d%d",&n,&m);
        for(int i = 0;i < n;i++) read(ip,i);
        for(int i = 0;i < m;i++) read(mac,i);
        for(int i = 0;i < m;i++){
            int ans = 0;
            for(int j = 0;j <n;j++){
                int temp = ip[j]&mac[i];
                it = M.find(temp);
                if(it == M.end()){
                    ans++;
                    M.insert(pair<int,bool>(temp,true));
                }
            }
            cout<<ans<<endl;
            M.clear();
        }
    }
    return 0;
}
</pre><pre name="code" class="cpp">
<a target=_blank href="http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=584&pid=1004" style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1004</a>
这个题目似乎只要在中心能够放下第一个盘子就能获胜。

这个题没写也没法交...看看以后能不能交


1005 

这个题目只要发现了棋子行走的特点就能搞出来。对于王来说,每过一个单位时间,能走到的位置就向外扩一圈,而圈内部的任意位置都可以在t时间走到。对于马来说,只要能在t的时间走到的位置,均可以在t + 2*k的时间走到。因此我们进行两次bfs,对每一个格子分别标记马和王最早能到达的时间,然后把所有的格子都扫一遍,找最小值。 

1006 

一个dp题,三个状态dp[i][j][k],i代表当前的长度,j代表以什么数结尾,k代表现在是上升还是下降,dp数组保存的是平均单调区间数和区间总长度除以总个数。因此两个一除便是平均单调区间长度。第二问即求出了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值