補一張圖
我們嘗試把圓上的扇形轉化成直線上的矩形——我們維護[1,2m]的區間,那麼每個能產生貢獻的子區間的長度第k大的半徑的平方的總和就是answer了。
怎麼轉化呢?左端點為a1+m+1,右端點為a2+m。為什麼要+m?因為原先的範圍是[-m,m]的,所以整體右移。為什麼左端點要+1?因為我們維護的是區間,所以這裡的每乙個下標表示的是以該position為右端點,長度為1的區間。
我們先按照半徑長度從大到小排序,如果乙個區間覆蓋數量超過k個,就不需要再處理了。(優化時間複雜度)
之後就是線段樹操作了。我們在更改的同時求出答案。(其實分開寫也行,就是要注意因為我們乘上的係數使然,所以區間必須也是當前的修改區間)
minn表示該區間的所有子區間覆蓋量的min,maxx是該區間的所有子區間的覆蓋量的max。
注意我們的siz是由左右子區間合併而來的。所以產生貢獻之後,記得賦值為0,這樣就不會對它的父親區間產生貢獻了。
**如下:
#include#include#include#include#include#define maxn 2000010
using namespace std;
int n,m,k;
long long ans=0;
struct nodenode[maxn];
struct node2t[maxn<<2];
inline bool cmp(struct node x,struct node y)
inline int ls(int x)
inline int rs(int x)
inline void push_up(int x)
inline void build(int x,int l,int r)
int mid=(l+r)>>1;
build(ls(x),l,mid);
build(rs(x),mid+1,r);
push_up(x);
}inline void solve(int x,int k)
inline void push_down(int x)
}inline int update_query(int x,int ll,int rr)
int cur_ans=0;
push_down(x);
cur_ans+=update_query(ls(x),ll,rr);
cur_ans+=update_query(rs(x),ll,rr);
push_up(x);
return cur_ans;
}push_down(x);
int mid=(l+r)>>1;
int cur_ans=0;
if(ll<=mid) cur_ans+=update_query(ls(x),ll,rr);
if(midnode[i].r)
ans+=1ll*cur_ans*node[i].c*node[i].c;
//printf("i=%d ans=%lld\n",i,ans);
}printf("%lld\n",ans);
return 0;
}
SHOI2013 超級跳馬
我是常年遊蕩於題解區的幽靈。直觀的想法就是字首和 差分優化dp,但還有些比較奇妙的方法or trick f i j f i 1 j 1 f i 1 j f i 1 j 1 color 因為可以一步跳到 f i j 的狀態也可以一步跳到 f i 2 j 反過來也成立 只考慮從左邊某個特定的列的轉移矩陣...
矩陣乘 Shoi2013 超級跳馬
問題 f shoi2013 超級跳馬 時間限制 1 sec 記憶體限制 256 mb 題目描述 現有乙個n行m列的棋盤,乙隻馬欲從棋盤的左上角跳到右下角。每一步它向右跳奇數列,且跳到本行或相鄰行。跳越期間,馬不能離開棋盤。例如,當n 3,m 10時,下圖是一種可行的跳法。試求跳法種數mod 3001...
bzoj 4417 Shoi2013 超級跳馬
題意 現有乙個n行m列的棋盤,乙隻馬欲從棋盤的左上角跳到右下角。每一步它向右跳奇數列,且跳到本行或相鄰行。試求跳法種數mod 30011。題解 dp 矩陣乘法 快速冪 設f i j 表示走到第2i 1列,第 j 行的方案數,g i j 表示走到第2i 列,第j行的方案數。那麼f i j k 1i 1...