紹一集訓Round#1

到了以後看題,T1一看發現真熟悉,和以前作的一道題真的像,而後心裏:html

這裏是紹一啊,不可能就出這麼簡單的題git

我題意沒理解錯啊,這不是單獨計算每條邊的貢獻麼算法

維護一我的數的大小,而後直接搞一波就能夠了吧性能

......(狂碼5mins)spa

(一測樣例,過了)code

這麼爽,趕忙寫個暴力+對拍htm

......(15mins later)blog

竟然過了,瑟瑟發抖莫名自信ci

而後就真的A了T1不過真的很水get

而後開T2,這種計算循環節的題目,lcm內的確定能夠作的啊

結果結合數據範圍直接寫了個暴力60pts的算法。

以後沒有什麼思路,感受再推下去也寫不出,而後就開始卡常

幾發以後開T3,發現這個式子是\(O(n^3)\)計算的,還要套上一個\(q\)感受要完

發現那個最大值很好求,直接RMQ以後\(O(1)\)求就能夠了,但\(O(qn^2)\)至於30pts

想一想怎麼\(O(qn)\),而後就開始畫圖,結果YY着:

枚舉每一個點爲最大值的狀況感受能夠

而後找出左右邊界的位置便可

這什麼鬼,不是單調棧水一水的東西嗎

(......立刻碼完調過樣例)

而後一算大概210左右,而後就開始拍T3

期間上廁所遇到了yekehe,跟他說基準分絕壁210,他也表示十分認同。

回來發現拍了10mins後T3WA了!

嚇得我一哆嗦,而後發現太大調不出,因此改了下數據範圍,而後一直沒拍出來。

後來感受是個很小的細節flag最後忐忑的交了上去。

結果最後一測170,T1A了,T2多卡了10分,但T3爆零了。

後來一看sol發現沒有考慮兩個數相同的狀況,我單調棧都寫了小於號,但實際上應該是一個地方加等於的。

而後發現yekehe也和我同樣T3爆零了。

最後看了下排名220已經很高了(最快的Rank2),這裏%%%一發X_o_r dalao220pts

前面已經講了不少了,這裏簡略的給出題解:

城市

題目要求的是\(\sum u\sum v\ dis(u,v)\)

咱們單獨考慮每一條邊對答案的貢獻。咱們DFS預處理出兩邊的人數,最後乘起來就行了。

由於這是一棵樹,而樹上路徑惟一。所以他們必然通過這條邊。

CODE

#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
const int N=1000005,mod=1e9+7;
struct edge
{
    int to,next;
}e[N<<1];
int head[N],n,x,y,cnt,num[N],tot,ans;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void double_add(int x,int y)
{
    e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
    e[++cnt].to=x; e[cnt].next=head[y]; head[y]=cnt;
}
inline void inc(int &x,int y)
{
    if ((x+=y)>=mod) x-=mod;
}
inline void DFS(int now,int fa)
{
    register int i; inc(num[now],now);
    for (i=head[now];~i;i=e[i].next)
    if (e[i].to!=fa) DFS(e[i].to,now),inc(num[now],num[e[i].to]);
}
int main()
{
    freopen("city.in","r",stdin); freopen("city.out","w",stdout);
    register int i; read(n);
    memset(head,-1,sizeof(head));
    for (i=1;i<n;++i)
    read(x),read(y),double_add(x,y);
    DFS(1,-1); tot=1LL*(n+1)*n/2%mod;
    for (i=1;i<=n;++i)
    inc(ans,(1LL*num[i]*((tot-num[i]+mod)%mod))%mod);
    return printf("%d",ans),0;
}

人工智障

因爲我比較菜,到如今也不是很理解正解的玄學推導。

所以這裏推個dalao寫的blog:現場A掉此題的YPC dalao

而後給出個人抄來的CODE(寫法可能有細微區別)

#include<cstdio>
#include<cctype>
using namespace std;
typedef long long LL;
const LL N=500005;
LL k,ans1,ans2,tot1,tot2,t,num[3],n,m,a[N],b[N],g;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(LL &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline LL gcd(LL n,LL m)
{
    return m?gcd(m,n%m):n;
}
int main()
{
    freopen("ai.in","r",stdin); freopen("ai.out","w",stdout);
    register LL i,j,s; read(n); read(m); read(k);
    for (i=1;i<=n;++i) read(a[i]);
    for (i=1;i<=m;++i)read(b[i]); g=gcd(n,m);
    for (i=1;i<=g;++i)
    {
        num[0]=num[1]=num[2]=0;
        for (j=i;j<=n;j+=g) ++num[a[j]];
        for (j=i;j<=m;j+=g) ans1+=num[(b[j]+2)%3],ans2+=num[(b[j]+1)%3];
    }
    t=n/g*m; ans1*=k/t; ans2*=k/t; k%=t;
    if (k)
    {
        for (s=1;s<=g;++s)
        {
            num[0]=num[1]=num[2]=0; LL tail=s;
            for (i=1;i<=(k-1)/n+1;++i)
            {
                ++num[b[tail]]; if (i<=(k-1)/n) tail=(tail+n-1)%m+1;
            }
            for (i=s;;i=(i+n-1)%m+1)
            {
                for (j=i;j<=n;j+=m)
                {
                    if (j>(k-1)%n+1) --num[b[tail]];
                    ans1+=num[(a[j]+1)%3]; ans2+=num[(a[j]+2)%3];
                    if (j>(k-1)%n+1) ++num[b[tail]];
                }
                tail=(tail+n-1)%m+1; ++num[b[tail]]; --num[b[i]];
                if ((i+n-1)%m+1==s) break;
            }
        }
    }
    return printf("%lld %lld",ans1,ans2),0;
}

循環

仍是一道很套路的題,咱們考慮對原來的式子:

\(\sum_{L=l}^{r}\sum_{R=L}^{r}max(x_{i})(L<=i<=R)\)

咱們加一個RMQ就能夠\(O(1)\)查詢了。

而後考慮計算當一個點爲最大值是它兩邊最遠能擴展到哪裏。

這仍是先後兩遍單調棧就能夠解決的事情。

而後50pts到手。到後面的話因爲套路性太強,之後再來討論:

50~70ptsCODE(看機子的性能來決定分數)

#include<cstdio>
#include<cctype>
using namespace std;
const int N=500005;
int n,a[N],stack[N],top,front[N],back[N],num[N],q,l,r;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(long long x)
{
    if (x>9) write(x/10);
    putchar(x%10+'0');
}
inline long long solve(int l,int r)
{
    register int i; long long tot=0;
    for (i=l;i<=r;++i)
    {
        int L=front[i]<l?l-1:front[i],R=back[i]>r?r+1:back[i];
        tot+=1LL*a[i]*(i-L)*(R-i);
    }
    return tot;
}
int main()
{
    freopen("calc.in","r",stdin); freopen("calc.out","w",stdout);
    register int i; read(n); read(q);
    for (i=1;i<=n;++i) read(a[i]);
    for (i=1;i<=n;++i)
    {
        while (top&&stack[top]<=a[i]) --top;
        front[i]=num[top];
        stack[++top]=a[i]; num[top]=i;
    }
    for (top=0,num[0]=n+1,i=n;i>=1;--i)
    {
        while (top&&stack[top]<a[i]) --top;
        back[i]=num[top];
        stack[++top]=a[i]; num[top]=i;
    }
    while (q--)
    {
        read(l); read(r);
        write(solve(l,r)); putchar('\n');
    }
    return 0;
}

而後光榮炸裂。

相關文章
相關標籤/搜索