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; }