给你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>
这个题目似乎只要在中心能够放下第一个盘子就能获胜。
这个题没写也没法交...看看以后能不能交
这个题目只要发现了棋子行走的特点就能搞出来。对于王来说,每过一个单位时间,能走到的位置就向外扩一圈,而圈内部的任意位置都可以在t时间走到。对于马来说,只要能在t的时间走到的位置,均可以在t + 2*k的时间走到。因此我们进行两次bfs,对每一个格子分别标记马和王最早能到达的时间,然后把所有的格子都扫一遍,找最小值。
一个dp题,三个状态dp[i][j][k],i代表当前的长度,j代表以什么数结尾,k代表现在是上升还是下降,dp数组保存的是平均单调区间数和区间总长度除以总个数。因此两个一除便是平均单调区间长度。第二问即求出了。