https://www.luogu.org/problem/P3937
题目描述
有nn盏灯环形排列,顺时针依次标号为1\cdots n1⋯n。初始时刻为00,初始时刻第ii盏灯的亮灭a_iai给定,00表示灭,11表示亮。下一时刻每盏灯的亮灭取决于当前时刻这盏灯与顺时针方向下一盏灯的亮灭。若两盏灯状态相同,则下一时刻该灯灭,否则该灯亮。
试求时刻tt第kk盏灯的状态。
输入格式
第一行,三个整数,分别为n, t, kn,t,k。
第二行,共nn个整数,分别为00或11,代表a_iai。
输出格式
共一行,一个数,00或11,代表时刻tt第kk盏灯的状态。
输入输出样例
输入 #14 2 1 1 0 1 0输出 #1
0
说明/提示
对于25\%25%的数据,有1\leq t, k\leq n\leq 10001≤t,k≤n≤1000。
对于60\%60%的数据,有1\leq t, k\leq n\leq 10^51≤t,k≤n≤105。
对于100\%100%的数据,有1\leq t, k\leq n\leq 3*10^61≤t,k≤n≤3∗106。
找了下规律,发现 N(log(N)/log(2)) 作法
先假设 k=1 ,我们就看答案要的这一位
0 时刻,ans = a1
1 时刻,ans = a1^a2
2 时刻,ans = a1^a2^a2^a3 = a1^a3
3 时刻,ans = a1^a2^a3^a4
4 时刻,ans = a1^a2^a2^a3^a3^a4^a4^a5 = a1^a5
5 ......................................................................................
6 ............................................................................................
7 ...................................................................................................
8 时刻,ans = ......................................................................................... = a1^a9
这样 log(N)/log(2) 就出来了,事实上并不会T
与倍增法求LCA有相似处
#include<iostream> #include<cstdio> #define ri register int #define u int namespace opt { inline u in() { u x(0),f(1); char s(getchar()); while(s<'0'||s>'9') { if(s=='-') f=-1; s=getchar(); } while(s>='0'&&s<='9') { x=(x<<1)+(x<<3)+s-'0'; s=getchar(); } return x*f; } } using opt::in; #include<cmath> #include<algorithm> #define NN 3000005 namespace mainstay { u N,T,K,a[NN<<1]; inline void solve() { while(~scanf("%d%d%d",&N,&T,&K)) { for(ri i(1); i<=N; ++i) a[i]=a[i+N]=in(); u ans(a[K]); while(T) { u k(std::log(T)/std::log(2)); u p(std::pow(2,k)); ans^=a[K+p]; for(ri i(1); i<=N; ++i) a[i]^=a[i+p]; for(ri i(1); i<=N; ++i) a[i+N]=a[i]; T-=std::pow(2,k); } printf("%d\n",ans); } } } int main() { //freopen("TLE.in","r",stdin); //freopen("TLE.out","w",stdout); std::ios::sync_with_stdio(false); mainstay::solve(); }