noip模擬64(待補)
A. 三元組
簽到題,樹狀陣列亂寫就行了.
A_code
#include<bits/stdc++.h> using namespace std; namespace BSS { #define ll long long int #define ull unsigned ll #define lf double #define lbt(x) (x&(-x)) #define mp(x,y) make_pair(x,y) #define lb lower_bound #define ub upper_bound #define Fill(x,y) memset(x,y,sizeof x) #define Copy(x,y) memcpy(x,y,sizeof x) #define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout) inline ll read() { ll res=0; bool cit=1; char ch; while(!isdigit(ch=getchar())) if(ch=='-') cit=0; while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return cit?res:-res; } } using namespace BSS; const ll N=1e5+21; ll Ts,n,mod,ans,cnt; ll vis[N],bin[N]; struct Bit_Array{ ll res; ll c[N<<1]; inline void update(ll x,ll w){ if(x<=0){ c[0]+=w; return ; } for(;x<mod;x+=lbt(x)) c[x]+=w; } inline void del(ll x){ if(x<=0){ c[0]=0; return ;} for(;x<mod;x+=lbt(x)) c[x]=0; } inline ll query(ll x){ res=0+c[0]*(x>=0); for(;x>0;x&=(x-1)) res+=c[x]; return res; } inline ll ask(ll l,ll r){ return query(r)-query(l-1); } }bit; signed main(){ File(exclaim); Ts=read(); ll l,r,tmp=0; for(int T=1;T<=Ts;T++){ n=read(),mod=read(),ans=0,cnt=0; for(ll i=n;i>=1;i--){ tmp=i*i*i%mod,bit.update(tmp,1); if(!vis[tmp]) vis[tmp]=1,bin[++cnt]=tmp; if(i%mod==0) ans+=bit.ask(0,mod-1)*(i/mod); else { l=(i*i+1)%mod,r=(i*i+i)%mod; ans+=bit.ask(0,mod-1)*(i/mod); if(l<=r) ans+=bit.ask(l,r); else ans+=bit.ask(l,mod-1)+bit.ask(0,r); } } for(int i=1;i<=cnt;i++) bit.del(bin[i]),vis[bin[i]]=0; printf("Case %d: %lld\n",T,ans); } exit(0); }
B. 簡單的字串
不會迴文樹,也不會 \(manacher\).
考場上就想到了這個題目的所有性質.
但是差一個 \(Border\) 理論 (膜拜這位 \(dalao\),講得很清晰.)
考後看到題解中說到只會跳兩三次,於是覺得暴跳 \(kmp\) 就行了.
雖然這樣也能 \(A\),但實際上覆雜度是假的,可以被卡成 \(O(n^3)\).
本以為這樣就結束了,但是多虧 \(Yubai\) 來問我這題做法(因為貌似只有我一個人是用 \(kmp\) \(A\) 掉的).
實際上我們完全可以去掉一維.
如果會了上面的理論,那麼這就是個板子題了,現在正式進入題解.
我們發現答案其實就是由 \(A+B+B+A\)
考慮得到 \(A\) :
然後我們在每個子區間 \([l,r]\) 分別處理出來 \(ta\) 的\(border\).
我們發現這個 \(border\) 長度可能大於 \(\dfrac{r-l+1}{2}\),考慮把 \(ta\) 縮小到一般長度以內.
只要學會上面的理論,這個東西還是很好說的.
設子串 \([l,r]\) 為 \(S\).
由於大於 \(\dfrac{len_s}{2}\) 的 \(Border\) 的長度為一個等差序列。
所以可以求出 \(S\) 的\(Max\ Border\),然後求出 \(Max\ Border\)
公差就是 \(M_1\ - \ M_2\).
於是 \(A\) 便可以跳公差求出了.
考慮得到 \(B\) :
我們可以列舉中點,然後 \(Hash\) 得到中間 \(B\) 的部分.
這裡建議結合 \(PPT\) 中給出的題解一起理解.
到此我們得到了 \(A\) 與 \(B\)..
我們得到了最長的 \(A\) 和最長的 \(B\) 之後,餘下的我們分別進行判斷.
這裡都要判斷,並不取決於 \(A\) 或 \(B\) 的相對大小而選擇捨棄哪一個.
這裡有 \(Yubai\) 的手模樣例:1 1 1 1 1 1 2 1 1 2 1 1 1 1 1 1 . 樣例說明並不能捨棄某種判斷.
至此本題結束,並膜掰.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
#define ll int
#define ull unsigned ll
#define lf double
#define lbt(x) (x&(-x))
#define mp(x,y) make_pair(x,y)
#define lb lower_bound
#define ub upper_bound
#define Fill(x,y) memset(x,y,sizeof x)
#define Copy(x,y) memcpy(x,y,sizeof x)
#define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
inline ll read() {
ll res=0; bool cit=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return cit?res:-res;
}
} using namespace BSS;
const ll N=6e3+21;
const ull P=131;
ll m,n,ans;
ll nxt[N][N],bd[N][N];
ull pre[N],po[N],sp[N];
inline void PUT(ll l,ll r){ for(int i=l;i<=r;i++) cout<<sp[i]<<' '; puts(""); }
inline ull getsh(ll l,ll r){
return 1u*pre[r]-1u*pre[l-1]*po[r-l+1];
}
inline void getnxt(){
for(int st=1;st<=n;st++){
for(int i=st-1;i<=n;i++) nxt[st][i]=st-1;
for(int i=st+1,j=st-1;i<=n;i++){
while(j>st-1 and sp[i]!=sp[j+1]) j=nxt[st][j];
if(sp[i]==sp[j+1]) nxt[st][i]=++j;
else nxt[st][i]=st-1;
}
}
}
inline void getbord(){
for(int mid=1;mid<n;mid++){ // 列舉中點
ll lmt=min(mid,n-mid);
for(int l=1;l<=lmt;l++){
bd[mid][l]=bd[mid][l-1];
if(getsh(mid-l+1,mid)==getsh(mid+1,mid+l)) bd[mid][l]=l;
}
}
}
inline bool check(ll l,ll r){
ll mid=(l+r)>>1,nownxt=nxt[l][r];
if(nownxt>mid){
ll nxtnxt=nxt[l][nownxt],delta=nownxt-nxtnxt;
nownxt=nownxt-delta*((nownxt-mid)/mid);
if(nownxt>mid) nownxt=nxt[l][nownxt];
}
if(nownxt==mid) return 1;
if(getsh(nownxt+1,mid)==getsh(mid+1,2*mid-nownxt)) return 1;
ll len=r-mid,nowbd=bd[mid][len],br=mid+nowbd,bl=mid-nowbd+1;
if(l==bl and r==br) return 1;
if(getsh(l,bl-1)==getsh(br+1,r)) return 1;
return 0;
}
signed main(){
File(s);
n=read(),po[0]=1;
for(int i=1;i<=n;i++){
sp[i]=read();
pre[i]=pre[i-1]*P+sp[i],po[i]=po[i-1]*P;
}
getnxt(),getbord();
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j+=2){
if(nxt[i][j]<i) continue;
ans+=check(i,j);
}
}
printf("%d\n",ans),exit(0);
}