题目大意:
有n只猫,现在进行一轮喂食操作,一轮操作包括k次,每一次有以下三种选择:
1.给第i只猫一颗食物(ai++)
2.让第i只猫吃掉现有食物(ai = 0)
3.交换第i,j两只猫的食物数量(swap(ai, aj))
然后进行m轮同样的操作,问最后每只猫的食物数量。n≤100,k≤100,m≤10⁸。
分析:
我看到网上给的做法基本都是矩阵,所以写一个不同的做法。矩阵的大方向很容易想到,因为变换次数为8次方级别,自然联想到矩阵的幂。但是实际构造矩阵并不容易,我短暂思索之后没想出来,然后换了一个思路,想出另外一个办法了。
以ai表示当前的序列,经过一轮变换(不是一次,直接考察一轮)之后,ai可能变为以下三种结果:
1.ai+k
2.aj+k
3.0
现在把变换结果构造成一个图:
情况1,2:添加点j到点i的单向边,权重为k(情况1则添加点i到自身的边)
情况3:添加点0到点i的单向边,注意n个点从1开始编号
构造出的图包括两种子图:环以及从点0出发的链
对于环,以环为周期,环中的每个点经过一个周期之后都会增加环的总权重。
对于链,很容易证明,经过ti次操作后ai为一个固定的值,这里ti表示链中每一个点i到点0的距离。
理解了这两条性质,题目就很容易了。这种做法的时间复杂度为:构造图O(k),寻找周期O(n),求结果O(n²),因些总的时间复杂度为O(n²)。而矩阵做法为O(n³log(m))。
#include <iostream>
#include <cstdio>
#define MEMSET(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int MAX_N = 100 + 2;
int t[MAX_N];
int add[MAX_N];
int edge[MAX_N];
int wht[MAX_N];
int vis[MAX_N];
int main(int argc, char *argv[])
{
int n, m, k, a, b;
char ch;
while (scanf("%d%d%d", &n, &m, &k), n || m || k)
{
for (int i = 1; i <= n; i++)
{
edge[i] = i;
wht[i] = 0;
}
while (k--)
{
scanf("\n%c", &ch);
if (ch == 'g')
{
scanf("%d", &a);
wht[a]++;
}
else if (ch == 's')
{
scanf("%d%d", &a, &b);
swap(edge[a], edge[b]);
swap(wht[a], wht[b]);
}
else
{
scanf("%d", &a);
edge[a] = 0;
wht[a] = 0;
}
}
MEMSET(vis, 0);
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
int pre = edge[i];
add[i] = wht[i];
t[i] = 1;
while (pre && pre != i)
{
vis[pre] = true;
add[i] += wht[pre];
pre = edge[pre];
t[i]++;
}
if (pre == i)
{
pre = edge[i];
while (pre != i)
{
t[pre] = t[i];
add[pre] = add[i];
pre = edge[pre];
}
}
else
{
t[i] = -t[i];
int lst = i;
pre = edge[i];
while (pre)
{
t[pre] = t[lst] - 1;
add[pre] = add[lst] - wht[lst];
lst = pre;
pre = edge[pre];
}
}
}
}
for (int i = 1; i <= n; i++)
{
ll ans;
if (t[i] > 0)
{
ans = m / t[i] * (ll)add[i];
int cnt = m % t[i], pos = i;
while (cnt--)
{
ans += wht[pos];
pos = edge[pos];
}
}
else
{
t[i] = -t[i];
if (m >= t[i]) ans = add[i];
else
{
ans = 0;
int cnt = m, pos = i;
while (cnt--)
{
ans += wht[pos];
pos = edge[pos];
}
}
}
if (i < n) printf("%lld ", ans);
else printf("%lld\n", ans);
}
}
return 0;
}