USACO 2020 February Contest, Silver Problem 1. Swapity Swapity Swap
Farmer John's NN cows (1≤N≤1051≤N≤105) are standing in a line. The iith cow from the left has label ii for each 1≤i≤N1≤i≤N.
Farmer John has come up with a new morning exercise routine for the cows. He has given the cows MM pairs of integers (L1,R1)…(LM,RM)(L1,R1)…(LM,RM), where 1≤M≤1001≤M≤100. He then tells the cows to repeat the following MM-step process exactly KK (1≤K≤1091≤K≤109) times:
- For each ii from 11 to MM:
- The sequence of cows currently in positions Li…RiLi…Ri from the left reverse their order.
After the cows have repeated this process exactly KK times, please output the label of the iith cow from the left for each 1≤i≤N1≤i≤N.
SCORING:
- Test case 2 satisfies N=K=100N=K=100.
- Test cases 3-5 satisfy K≤103K≤103.
- Test cases 6-10 satisfy no additional constraints.
INPUT FORMAT (file swap.in):
The first line contains NN, MM, and KK. For each 1≤i≤M1≤i≤M, line i+1i+1 line contains LiLi and RiRi, both integers in the range 1…N1…N, where Li<RiLi<Ri.
OUTPUT FORMAT (file swap.out):
On the iith line of output, print the iith element of the array after the instruction string has been executed KK times.
SAMPLE INPUT:
7 2 2 2 5 3 7
SAMPLE OUTPUT:
1 2 4 3 5 7 6
Initially, the order of the cows is [1,2,3,4,5,6,7][1,2,3,4,5,6,7] from left to right. After the first step of the process, the order is [1,5,4,3,2,6,7][1,5,4,3,2,6,7]. After the second step of the process, the order is [1,5,7,6,2,3,4][1,5,7,6,2,3,4]. Repeating both steps a second time yields the output of the sample.
Problem credits: Brian Dean
USACO 2020 February Contest, Silver Problem 1. Swapity Swapity Swap 题解(翰林国际教育提供,仅供参考)
[/hide]
(Analysis by Benjamin Qi)
First simulate the MM reversals in O(NM)O(NM) (or O(N+MlogN)O(N+MlogN) with a lazy balanced binary search tree, but that is outside the scope of silver). After this, let p[i]p[i] denote the ii-th cow from the right. It suffices to find
for every ii. To compute this expression for a single index ii, first find the minimum positive integer xx such that px[i]=ipx[i]=i. We can refer to the sequence
Now it is easy to compute pK[j]=pK(modx)[j]pK[j]=pK(modx)[j] for all jj located on the cycle in O(x)O(x) time.
As every index of the permutation lies on exactly one cycle, the sum of the cycle lengths is equal to NN, meaning that this part of the solution runs in O(N)O(N) time.
Dhruv Rohatgi's code:
#include <iostream> #include <algorithm> #include <vector> using namespace std; #define MAXN 100000 int N,M,K; int l[100],r[100]; int p[MAXN]; int cc[MAXN]; int pos[MAXN]; vector<int> A[MAXN+1]; int ans[MAXN]; int main() { freopen("swap.in","r",stdin); freopen("swap.out","w",stdout); cin >> N >> M >> K; for(int i=0;i<M;i++) { cin >> l[i] >> r[i]; l[i]--,r[i]--; } for(int i=0;i<N;i++) { p[i] = i; for(int j=0;j<M;j++) if(p[i] >= l[j] && p[i] <= r[j]) p[i] = r[j] + l[j] - p[i]; } int C = 1; for(int i=0;i<N;i++) if(!cc[i]) { cc[i] = C; A[C].push_back(i); int j = p[i]; if(j != i) pos[j] = 1; while(j != i) { A[C].push_back(j); cc[j] = C; if(p[j]!=i) pos[p[j]] = 1 + pos[j]; j = p[j]; } C++; } for(int i=0;i<N;i++) ans[A[cc[i]][(pos[i] + K)%A[cc[i]].size()]] = i; for(int i=0;i<N;i++) cout << ans[i]+1 << '\n'; }
An alternative approach is to use binary exponentiation. Calculate p2k[i]p2k[i] for each non-negative integer kk such that 2k≤K2k≤K, and then combine the appropriate permutations together to get pK[k]pK[k]. This approach runs in O(NlogK)O(NlogK) time.
Nick Wu's code:
import java.io.*; import java.util.*; public class Solution { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("swap.in")); PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("swap.out"))); StringTokenizer st = new StringTokenizer(br.readLine()); int n = Integer.parseInt(st.nextToken()); int m = Integer.parseInt(st.nextToken()); int k = Integer.parseInt(st.nextToken()); int[] to = new int[n]; { int[] l = new int[n]; for(int i = 0; i < n; i++) l[i] = i; while(m-- > 0) { st = new StringTokenizer(br.readLine()); int a = Integer.parseInt(st.nextToken()) - 1; int b = Integer.parseInt(st.nextToken()) - 1; while(a < b) { int t = l[a]; l[a] = l[b]; l[b] = t; a++; b--; } } for(int i = 0; i < n; i++) to[i] = l[i]; } int[] ret = new int[n]; for(int i = 0; i < n; i++) ret[i] = i+1; while(k > 0) { if(k%2 == 1) { ret = apply(ret, to); } k /= 2; if(k > 0) to = apply(to, to); } for(int val: ret) pw.println(val); pw.close(); } public static int[] apply(int[] l, int[] op) { int[] ret = new int[l.length]; for(int i = 0; i < ret.length; i++) { ret[i] = l[op[i]]; } return ret; } }
[/hide]