https://ac.nowcoder.com/acm/contest/19483/F
这道题乍一看像是个找规律或者模拟题, 实质上其每次操作都是固定的
那么这样的题目要如何带入前缀和来思考呢
我们将每一次的操作的序列状态的改变看作一个量
然后拿这个量形成的数组做前缀和
为什么可以这么转化呢,因为前缀和问题有一个共性:
每次的“增量”不相互影响,区间“量”等于区间前后侧的“积累量”之差
具体到这道题就是:
我每次只是交换杯子的位置,我的“增”就是进行交换,我的“减”就是之前的“增”的逆运算
然后用一个数组去记录“增”的积累,保证每一次减去k~n的积累量时
我用1到n的积累量减去1到k的积累量,得到的是:
用初始序列,从1开始,依次做第1到第k次的移动操作,再做第k到第1次的逆操作(即全部抵消)
再做第k~第n此的移动操作
细节看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m;
int f[N][10],sum[10];
int main(){
cin>>n>>m;
for(int i=0;i<10;i++) f[0][i]=i;//初始序列为0~9
for(int i=1;i<=n;i++){//记录1~n号操作的量
int a,b;
cin>>a>>b;
for(int j=0;j<10;j++) f[i][j]=f[i-1][j];
//当前序列为上一个序列进行交换的结果
swap(f[i][a],f[i][b]);
}
while(m--){
int l,r;
cin>>l>>r;
for(int i=0;i<10;i++) sum[f[l-1][i]]=i;
for(int i=0;i<10;i++) printf("%d ",sum[f[r][i]]);
printf("\n");
/*
这里为什么可以这么写呢
你把sum[]理解成我们前缀和求区间值的那个答案
本来我们要求的是a[l]+a[l+1]+……+a[r-1]+a[r]
但是要用前缀和我们可以简化为f[r]-f[l](f是a的前缀和数组)
但是我们只有a[0]+a[1]+……+a[r-1]+a[r](即f[r][])
-f[l]是什么呢,就是sum[],只是我们这里没有‘-’这个操作
本题的“+”和“-”都是赋值操作,这里就需要读者自行理解了
*/
}
return 0;
} 
京公网安备 11010502036488号