1. 程式人生 > >[bzoj5071][數論]小A的數字

[bzoj5071][數論]小A的數字

Description

小A成為了一個數學家,他有一串數字A1,A2…An
每次可以進行如下操作,選擇一個數字i,將(Ai-1,Ai,Ai+1)
變為(Ai-1 + Ai,-Ai,Ai+1 + Ai),特別地,若i=N,則(An-1,An)變為
(An-1 + An,-An).小A很好奇,能否通過若干次操作,得到他的幸運數列B1,B2…Bn.可是他太小,不會算,請你幫幫他

Input

第一行一個正整數T 表示資料組數。 每一組資料有三行,其中:
第一行一個正整數n,表示每一串數字的個數, 第二行n 個用空格隔開的整數a1 a2 a3 …. an, 第三行n 個用空格隔開的整數b1 b2 b3 … bn 。

Output

對於每一組資料,輸出一行”YES”或”NO”(不含雙引號),表示能否通過若 幹次操作得到b 數列。

Sample Input

2
6
1 6 9 4 2 0
7 -6 19 2 -6 6
4
1 2 3 4
4 2 1 3

Sample Output

YES
NO

Hint

Explanation for the Sample 第一組資料中,可以依次取i=2,4,5,每次得到的新數列如下: 第一次,
i=2,得到7,-6,15,4,2,0, 第二次, i=4,得到7,-6,19,-4,6,0, 第三次,
i=5,得到7,-6,19,2,-6,6,所以可以得到b 數列。 第二組資料中,不可能做到這一點。

題解

昨天晚上看見dalao們各種說O(n)於是怒想1h 順便掛了
字首和???好像有點道理
設sum[i]為 1~i 的字首和
來看三元組的變換操作
a[i-1],a[i],a[i+1]變為a[i-1]+a[i],-a[i],a[i+1]+a[i]
對於sum陣列,變換如下
sum[i-1],sum[i],sum[i+1]變為sum[i-1]+a[i],sum[i]-a[i]-a[i]+a[i],sum[i+1]-a[i]-a[i]+a[i]+a[i]
化簡一下
sum[i-1]+a[i]=sum[i]
sum[i]-a[i]-a[i]+a[i]=sum[i]-a[i]=sum[i-1]
sum[i+1]-a[i]-a[i]+a[i]+a[i]=sum[i+1]
變為sum[i],sum[i-1],sum[i+1]
對比sum[i-1],sum[i],sum[i+1]
可以發現,每一次變換三元組,都是交換前兩個位置的字首和陣列
那麼,我們搞出a和b的字首和。只要a和b的字首和換來換去可以換成一樣的,那麼就ok
怎麼判斷?字首和從小到大排一遍啊。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int a[110000],b[110000];
int n;
int main()
{
    int T,tmp;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        a[0]=b[0]=0;
        for(int i=1;i<=n;i++){scanf("%d",&tmp);a[i]=a[i-1]+tmp;}
        for(int i=1;i<=n;i++){scanf("%d",&tmp);b[i]=b[i-1]+tmp;}
        sort(a+1,a+1+n);
        sort(b+1,b+1+n);
        bool bk=false;
        for(int i=1;i<=n;i++)if(a[i]!=b[i]){bk=true;break;}
        if(bk==false)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}