bzoj 4722 由乃 線段樹 倍增 搜尋

2021-08-05 23:07:55 字數 1823 閱讀 2416

給乙個長為n的序列a,每個數在0到v - 1之間,有m次操作。

操作1:每次詢問乙個區間中是否可以選出兩個下標的集合x,y,滿足:

1.x和y沒有交集

2.設集合x中有乙個元素是i,則其對集合x的貢獻是a[i] + 1,要求集合x的元素的總貢獻和集合y的元素的總貢獻相等如果可以選出這兩個集合,輸出 yuno否則輸出 yuki

操作2:修改乙個區間l,r之間的數,使得所有l <= i <= r,a[i] = a[i] * a[i] * a[i] % v ,即區間立方

n , m <= 100000 , v <= 1000

乍一看根本不會做。

網上說只要序列長度大於13則答案必然為yuno。證明:因為子集數量有2l

en種,而權值則最多只有le

n∗1000

種,解方程可得le

n=13 。

有了這個結論這題就好做了。

對於乙個長度不超過13的序列,顯然每個數的係數只有0,1,-1三種,我們只要通過折半搜尋來判斷是否有貢獻相同的子集即可。

至於區間開三次方,我們可以通過線段樹打標記和倍增來實現。設bz[i,j]表示i3

2j,預處理後便可以在o(log)的複雜度內得到乙個數。

複雜度o(n

∗37)

,有點虛但實際上跑得賊快。

#include

#include

#include

#include

#include

using

namespace

std;

const

int n=100005;

const

int m=15000;

int n,m,v,bz[1005][20],size[n*4],a[n],tot,t[n],f[20];

bool vis[n],flag;

int read()

while (ch>='0'&&ch<='9')

return x*f;

}void prework()

void ins(int d,int l,int r,int x,int y)

int mid=(l+r)/2;

ins(d*2,l,mid,x,min(y,mid));

ins(d*2+1,mid+1,r,max(x,mid+1),y);

}int query(int d,int l,int r,int x)

int get(int x)

void dfs1(int x,int y,int z,int n)

dfs1(x+1,y,z,n);

if (flag) return;

dfs1(x+1,y+f[x]+1,z+1,n);

if (flag) return;

dfs1(x+1,y-f[x]-1,z+1,n);

}void dfs2(int x,int y,int z,int n)

dfs2(x+1,y,z,n);

if (flag) return;

dfs2(x+1,y+f[x]+1,z+1,n);

if (flag) return;

dfs2(x+1,y-f[x]-1,z+1,n);

}bool solve(int n)

int main()

for (int j=l;j<=r;j++) f[j-l+1]=get(j);

if (solve(r-l+1)) puts("yuno");

else

puts("yuki");}}

return

0;}

BZOJ4810 Ynoi2017 由乃的玉公尺田

對每個區間維護一下這個區間每個數有沒有,用bitset壓一下,這個用莫隊跑出來,然後就能判加減合不合法了 乘的話根號列舉一下就行了 include include include include include include include include include include incl...

bzoj4810 Ynoi2017 由乃的玉公尺田

由乃在自己的農田邊散步,她突然發現田裡的一排玉公尺非常的不美。這排玉公尺一共有n株,它們的高度參差不齊。由乃認為玉公尺田不美,所以她決定出個資料結構題 這個題是這樣的 給你乙個序列a,長度為n,有m次操作,每次詢問乙個區間是否可以選出兩個數它們的差為x,或者詢問乙個區間是否可以選出兩個數它們的和為x...

Ynoi2017 舌尖上的由乃

維護區間加和區間第k小。n 100000 分塊,設塊大小為k相信大家都會o n k log 2 n 的查詢和o k 的修改。什麼你不會o k 的修改?歸併啊歸併啊。那麼平衡規劃一下k n logn 總複雜度o nn l ogn include include include define fo i,...