550
AkariDaisuki
题意:f(X) = Waai + X + Akari + X + Daisuki,求F在f^k(S)种出现的次数,k<=10^10,S,F,A,B,C串长<=50
分析:显然F出现次数的增量之和X的前后缀有关,因此当到达一定次数之后X的前后缀就不会发生变化了,只要矩阵算算就可以了,次数较少的时候可以暴力
1000
XorLife
题意:一个无限大的平面,初始除了一个50*50的矩阵之外全部是0,每次每个格子=周围四个格子的数异或和再异或这个格子的数,问k次操作之后有多少个格子是1;
k≤109
分析:首先,这个过程具有叠加性,可以把最后的结果看成初始若干个1作用k步叠加而成;对一个1产生的效果模拟两步,发现两步之后只会影响奇偶性与初始1位置相同的格子,意味着假如两步两步走,会把平面根据奇偶性分成互不相关的两部分;因此我们可以根据整个图记忆化搜索(我是map了一个vector),状态很少
#include <cstdio>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <sstream>
#include <typeinfo>
#include <fstream>
#include <map>
using namespace std;
typedef vector<string> vs;
typedef pair<vs,int> pi;
typedef long long LL;
int di[5][2]={{1,0},{0,1},{-1,0},{0,-1},{0,0}};
class XorLife {
public:
map<pi,LL>Mp;
vs trans(vs from){
string tmp;
tmp.assign(2+from[0].size(),'.');
vs ret;
ret.assign(2+from.size(),tmp);
int n=ret.size(),m=ret[0].size();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
int cnt=0;
for(int d=0;d<5;d++){
int ni=i+di[d][0],nj=j+di[d][1];
if(ni>0&&ni<n-1&&nj>0&&nj<m-1&&from[ni-1][nj-1]=='o')cnt++;
}
if(cnt&1)ret[i][j]='o';
}
}
return ret;
}
long long countAliveCells(vector<string> field, int K) {
if(!field.size())return 0;
if(K&1)field=trans(field),K--;
// printf("K=%d\n",K);
// for(int i=0;i<field.size();i++)cout<<field[i]<<endl;
if(Mp.find(pi(field,K))!=Mp.end())return Mp[pi(field,K)];
if(!K){
LL ret=0;
for(int i=0;i<field.size();i++){
for(int j=0;j<field[0].size();j++){
ret+=field[i][j]=='o';
}
}
Mp[pi(field,K)]=ret;
return ret;
}
vector<string>nxt[2][2];
int n=field.size(),m=field[0].size();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
vs &ob=nxt[i&1][j&1];
if(ob.size()<=i/2)ob.push_back(string(""));
ob.back().push_back(field[i][j]);
}
}
LL ret=0;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++)
ret+=countAliveCells(nxt[i][j],K>>1);
}
Mp[pi(field,K)]=ret;
return ret;
return 0;
}
};