2019牛客第十場題解 C F

2021-09-26 07:45:44 字數 2685 閱讀 7556

題意:第i天在原來字串的基礎上在字串的前面或者後面新增乙個字元。問新增完字元後有多少種不同長度的迴圈節。

定義迴圈節為能把原字串分割成長度為k的乙個或多個部分。並且後面可以有或者沒有迴圈節的開頭部分。

也就是說 s[1]~s[n-x] == s[x+1]~ s[n] 則說明迴圈節為x 。

1.明顯,對於長度為len的字串,最少有乙個長度為len的迴圈節。

2.答案單調性,如果乙個長度為r的字串有長度為x的迴圈節。那麼長度x~r的所有字串都有長度為x的迴圈節(手動模擬下可以證明,將原字串不斷刪去開頭或者末尾的字元必然還是滿足s[1]~s[n-x] == s[x+1]~ s[n])

同理如果長度為r的字串沒有長度為x的迴圈節,那麼長度大於r的字串也一定沒有長度為x的迴圈節(同樣手動模擬在字串後面或者前面新增字元)

那麼我們可以想到,對長度為i=(1~n)的迴圈節我們在原字串的第i~第n階段 進行二分。找到擁有迴圈節i 的最大字串長度r

那麼i~r 都有迴圈節i, 結果加1 那麼我們可以通過字首和的方式將區間修改 變成單點修改。讓a[i]++, a[r+1]--  則字首和a[1]+...a[i]為

第i個階段的字串的迴圈節的種類數。

為了對字串二分。我們先把最終階段的字串hash,然後記錄一下每次變化後字串的左端點位置和右端點位置。

(具體做法是把head 設定為maxlen+1 ,tail 設定為maxlen+2 然後head往前減 tail往後加 最後把l[i]-=head, r[i]-=head則可以得到每個階段的左右端點)

然後每次二分check看l[i]~r[i]-x 是否等於x+1~r[i] 來判斷第i 階段可不可行。

總複雜度

#include#define ull unsigned long long

using namespace std;

const int maxn=2e6+6;

int n;

char s[10];

char ss[10];

int l[maxn],r[maxn],a[maxn];

struct hash

}ull query(int l,int r)

}hh;

bool check(int q,int x)

int main()

hh.get_hash(t+head+1);

for(int i=1;i<=n;i++)l[i]-=head,r[i]-=head;

for(int i=1;i<=n;i++)

a[r+1]--;

a[i]++;

}for(int i=1;i<=n;i++)

return 0;

}

題意:給你n個點,座標範圍為1e5 ,選不超過3條的橫線和不超過3條的豎線。相鄰線的距離固定為r,求位於這些線上的點的數量的最大值。

做法:用一棵線段樹維護值域上 第i, i+r, i+r*2 行上點的總數。 也就是說對於b[i] = a[i]+a[i+r]+a[i+r*2] 然後詢問整個區間的最大值。

(對於乙個x  他是 x,x-r , x-r*2 節點中的值, 所以這三個節點 需要變化)

#include#define ll long long

using namespace std;

const int maxn=100001;

int a[100005];

int b[100005];

int n,r;

vectorv[100005];

struct segment_tree

t[maxn*4];

void pushup(int o)

void build(int o,int l, int r)

int mid=(l+r)>>1;

build(o<<1,l,mid);

build(o<<1|1,mid+1,r);

pushup(o);

}void change(int o,int x,int d) // 單點更新

int mid=(t[o].l+t[o].r)>>1;

if(x<=mid)change(o<<1, x, d);

else change(o<<1|1, x, d);

pushup(o);

}int query(int o, int l, int r)

int mid=(t[o].l+t[o].r)>>1;

int mx=-1;

if(l<=mid)mx=max(query(o<<1,l,r),mx);

if(r>mid)mx=max(query(o<<1|1,l,r),mx);

return mx;

}int main()

for(int i=1;i<=maxn;i++)

build(1,1,maxn);

int ans=-1;

for(int i=1;i<=maxn;i++)

if(i+r<=maxn)

}if(i+r+r<=maxn)

}for(auto k:tmp)

ans=max(ans, (int)(tmp.size())+query(1,1,maxn) );

for(auto k:tmp)

}printf("%d\n",ans);

return 0;

}

2019牛客多校第十場

對於s n s n s n 考慮某個字母是從s n 1 s n 1 s n 1 轉移還是從s n 2 s n 2 s n 2 轉移 include define fo i,a,b for i a i b i define n 10005 using namespace std int t,n,q,p...

牛客第十場自閉

統計每個點連線邊的邊權和以及最大邊權,然後進行如下貪心 ll find ll x 將邊權存到了multisets x 這樣找到的ans是比答案大1倍的,因為每一條邊連向了兩個點,那麼每一條邊都被統計了2次答案,所以ans最後還要 2 也可以理解成以每個點為出發點,要往其他點連多少條邊 寫了詳細注釋 ...

2020牛客多校第十場 A

x 是乘法 以任意點為起點,一直以 2 x now p 第一類 做的話 或者3 x now p 第二類 會形成乙個或者多個環。環上有什麼特點。對於 某個數z,它所對應的後一位是y,當 2 x z p 3 x z p 相等的時候,這兩類的環在z後面的數y時一樣的。但是 上式化簡 2 x z n x p...