【POJ 3735】Training little cats(万万没想到の矩快)

【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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值