bzoj1411: [ZJOI2009]硬币游戏

传送门
手玩样例发现发现2^k变换之后,第i个位置的硬币情况只与它左右的第k+1个硬币有关。
如k=0,第3位硬币情况只与2和4位硬币有关。因为t可以拆成若干个2^k的和,于是对每个2^k进行O(n)的变换,总复杂度O(nlogt)。

#include<cstring>
#include<cmath>   
#include<cstdio>  
#include<iostream>  
#include<cstdlib>   
#include<algorithm>
#define ll long long
using namespace std;
ll a[200005],b[200005],n,t;
ll f(ll b,ll q){
    ll x=((b-q)%(2*n)+2*n-1)%(2*n)+1;
    ll y=(b+q-1)%(2*n)+1;
    if (!q) return a[x];
    if (!a[x]) return 0;
    if (a[x]!=a[y]) return 2;
    return 1;
}
void work(ll k,ll q){
    if (k==0) return;
    work(k/2,q*2);
    if (k%2){
        memset(b,0,sizeof(b));
        for (ll j=1;j<=n*2;j++) b[j]=f(j,q);
        swap(a,b);
    }
}
int main(){
    scanf("%lld%lld",&n,&t);
    for (int i=1;i<=n;i++) scanf("%lld",&a[i*2-1]);
    work(t,1);
    for (int i=1;i<2*n;i++) printf("%lld ",a[i]);
    printf("%lld",a[n*2]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值