【POJ 3735】Training little cats(万万没想到の矩快)
题目大意:
n只猫编号1~n
3中操作:
g i:给i一粒花生
e i:i把得到的花生全部吃掉
s i j:i与j交换花生。
给出一个操作序列,包含k个操作。
问执行这个序列m次,最后n只猫各自拥有的花生数量。
一直在找循环节,写了个暴力对拍和数据生成器,结果死活找不到合适的循环。
之后问了问度娘……对啊!矩快啊!。。。
100*100,然后重复次数这么大,我在干什么……
矩阵的初始化挺有趣的,跟之前做过的dp的初始化略有不同,类似于在线初始化,不是预制好的。
根据k个操作,让转移矩阵不断变化。矩阵中除了1~n每只猫当前花生数量外,还要有一个位置,给’1’。每次g i的时候从这里拿。然后e i就是清空i这行,s i j就是把第i行和第j行互换。
搞完后交上去会TLE。因为k是100,所以满矩阵最多有100个位置有数,其余位置都是0,所以在做矩阵乘法的时候判断一下
for(int k = 0; k <= len; ++k)
for(int i = 0; i <= len; ++i)
if(ans[i][k])
for(int j = 0; j <= len; ++j)
tmp.ans[i][j] += ans[i][k]*a.ans[k][j];
代码后面晒了数据生成器和暴力对拍工具
代码如下:
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <climits>
#include <ctime>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-8;
const int maxn = 233;
struct Matrix
{
LL ans[maxn][maxn];
int len;
void init(int l,int k)
{
char opt[3];
int a,b;
len = l;
for(int i = 0; i <= len; ++i)
for(int j = 0; j <= len; ++j)
ans[i][j] = i==j;
while(k--)
{
scanf("%s",opt);
if(opt[0] == 'g')
{
scanf("%d",&a);
ans[a][0]++;
}
else if(opt[0] == 'e')
{
scanf("%d",&a);
memset(ans[a],0,sizeof(ans[a]));
}
else
{
scanf("%d%d",&a,&b);
for(int i = 0; i <= len; ++i)
swap(ans[a][i],ans[b][i]);
}
}
}
void init(int l)
{
len = l;
for(int i = 0; i <= len; ++i)
for(int j = 0; j <= len; ++j)
ans[i][j] = i==j;
}
Matrix operator *(const struct Matrix a)const
{
Matrix tmp;
tmp.len = len;
memset(tmp.ans,0,sizeof(ans));
for(int k = 0; k <= len; ++k)
for(int i = 0; i <= len; ++i)
if(ans[i][k])
for(int j = 0; j <= len; ++j)
tmp.ans[i][j] += ans[i][k]*a.ans[k][j];
return tmp;
}
void prt()
{
for(int i = 0; i <= len; ++i)
{
for(int j = 0; j <= len; ++j)
{
printf("%lld ",ans[i][j]);
}
puts("");
}
puts("---------");
}
} mt,ans;
int n,k;
void Pow(LL b)
{
ans.init(n);
while(b)
{
if(b&1) ans = ans*mt;
b >>= 1;
mt = mt*mt;
}
}
int main()
{
fread("in.in");
fwrite("my.out");
LL m;
while(~scanf("%d%lld%d",&n,&m,&k) && (n+m+k))
{
mt.init(n,k);
Pow(m);
for(int i = 1; i <= n; ++i)
{
if(i != 1) putchar(' ');
printf("%lld",ans.ans[i][0]);
}
puts("");
}
return 0;
}
数据生成器:
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <climits>
#include <ctime>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-8;
const int maxn = 112345;
int main()
{
//fread("");
fwrite("in.in");
int n,m,k;
int t = 10;
srand(time(NULL));
while(t--)
{
n = 100;
m = 10000;
k = 100;
printf("%d %d %d\n",n,m,k);
srand(time(NULL));
while(k--)
{
int c = rand()%3;
if(c == 0)
{
printf("g %d\n",rand()%n+1);
}
else if(c == 1)
{
printf("e %d\n",rand()%n+1);
}
else printf("s %d %d\n",rand()%n+1,rand()%n+1);
}
}
puts("0 0 0");
return 0;
}
对拍:
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <climits>
#include <ctime>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread(ch) freopen(ch,"r",stdin)
#define fwrite(ch) freopen(ch,"w",stdout)
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const double eps = 1e-8;
const int maxn = 112345;
struct Action
{
char opt[3];
int a,b;
} act[233];
LL n,m,k;
LL ans[2][233];
void cal(int pos)
{
for(int i = 0; i < k; ++i)
{
if(act[i].opt[0] == 'g') ans[pos][act[i].a]++;
else if(act[i].opt[0] == 'e') ans[pos][act[i].a] = 0;
else swap(ans[pos][act[i].a],ans[pos][act[i].b]);
}
}
int main()
{
fread("in.in");
fwrite("out.out");
while(~scanf("%lld%lld%lld",&n,&m,&k) && (n+m+k))
{
for(int i = 0; i < k; ++i)
{
scanf("%s",act[i].opt);
scanf("%d",&act[i].a);
if(act[i].opt[0] == 's') scanf("%d",&act[i].b);
}
memset(ans,0,sizeof(ans));
while(m--)
cal(0);
for(int i = 1; i <= n; ++i)
{
if(i != 1) putchar(' ');
printf("%lld",ans[0][i]);
}
puts("");
}
return 0;
}