-
Problem link:
51-nod 1346 5级算法题 -
Probelm Description:
Problem Description:
函数f(n,m)
{
若n=1或m=1返回a[n][m];
返回f(n-1,m)异或f(n,m-1);
}
读入2<=n,m<=100
for i=2->100读入a[1][i]
for i=2->100读入a[i][1]
输出f(n,m)
发现当n,m较大时程序变得异常缓慢。
小b经过一番思考,很快解决了这个问题。
这时小c出现了,我将n,m都增加131072,你还能解决吗?
相对的,我会读入2->131172的所有a[1][i]和a[i][1]。
小b犯了难,所以来找你,你能帮帮他吗?
输入
第一行读入131171个正整数,表示i=2->131172的a【1】【i】(1<=a[1][i]<=1000000000)。
第二行读入131171个正整数,表示i=2->131172的a【i】【1】(1<=a[i][1]<=1000000000)。
第三行读入一个正整数Q(1<=Q<=10000),表示询问的次数。
接下来Q行,每行两个数n,m(2<=n,m<=100),表示每一组询问。
输出
Q行,每行为f(n+131072,m+131072)
输入样例
2 3 4 5 6 7 8 … 131171 131172
2 3 4 5 6 7 8 … 131171 131172
3
2 2
2 3
2 4
输出样例
0
0
131072
-
解题思路:
首先:
递推易得:
f[n][m]=f[n-2^x] [m] ^ f[n][m-2^x] (x=0,1,2,3…)此题目中须知:131072是2的18次方,则此题目只需要记忆化搜索一下求出f[100][131172]与f[131172][100]的两个数组的值即可。改天补一个用递推完成的代码,现在已经凌晨两点多了,我比较懒,不想补了。我看别人都是用递推写的,就我写了个记忆化搜索。 -
AC code:
#include<iostream>
#include<cstring>
using namespace std;
const int N=131175;
int a[N],b[N],n,m,t,q,dp1[105][N],dp2[N][105];
int f1(int n,int m){
if(dp1[n][m]!=-1)return dp1[n][m];
if(n==1)return dp1[n][m]=a[m];
else if(m==1)return dp1[n][m]=b[n];
else return dp1[n][m]=f1(n-1,m)^f1(n,m-1);
}
int f2(int n,int m){
if(dp2[n][m]!=-1)return dp2[n][m];
if(n==1)return dp2[n][m]=a[m];
else if(m==1)return dp2[n][m]=b[n];
else return dp2[n][m]=f2(n-1,m)^f2(n,m-1);
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
for(int i=2;i<=131172;i++)cin>>a[i];
for(int i=2;i<=131172;i++)cin>>b[i];
memset(dp1,-1,sizeof(dp1));
memset(dp2,-1,sizeof(dp2));
f1(100,131172);
f2(131172,100);
cin>>q;
while(q--){
cin>>n>>m;
cout<<((dp1[n][m+131072])^(dp2[n+131072][m]))<<endl;
}
}