1. 程式人生 > >牛客國慶集訓派對Day4——I 連通塊計數(思維)

牛客國慶集訓派對Day4——I 連通塊計數(思維)

題目大意:

        小 A 有一棵長的很奇怪的樹,他由 n 條鏈和 1 個點作為根構成,第 i 條鏈有 ai 個點,每一條鏈的一端都與根結點相連。 現在小 A 想知道,這棵長得奇怪的樹有多少非空的連通子樹,你只需要輸出答案對 998244353 取模的值即可

題解:

      注意題目說的是每條鏈的一端都與根節點相連,只是這條鏈的最末端,端點與根節點相連,那些在這條鏈上卻非末端端點的點不與根節點相連

就像這個樣子

這樣的話,連通子樹的個數要分兩種情況

1.包含根節點

       對於每一條鏈,鏈的末端與根節點相連,構成了一個迴路,每一條鏈有a[i]個點,那麼就有在這條鏈選0個、選1個、選2個...選a[i]個,共a[i]+1種情況, ans1=\prod(a[i]+1)

要構成連通子樹,必須得是相連的,就是根-1,根-1-2,根-1-2-3......這樣的情況,不可能直接選中途的1-2這樣

2.不包含根節點

       對於每一條鏈,有a[i]個節點,那麼這條鏈能形成的子樹個數是 \frac{a[i]*(a[i]+1)}{2},這是通過挨個數找出的規律,

例如本圖最左邊的鏈,分別給點標號為1,2,3,4

子樹的個數為

①4個節點分別是1個

②1-2,1-2-3,1-2-3-4

③2-3,2-3-4,

④3-4

共10個

因為沒跟根節點連線,就不能乘了,要加起來,所以 ans2=\sum \frac{a[i]*(a[i]+1)}{2}

踩的坑:

      首先,這個題有除以2,但是不用求逆元,當能夠保證整除的情況下不需要求逆元(a[i]*(a[i]+1)也一定能夠整除2),當是分數的情況下才需要求逆元(又漲姿勢了),但是求了也沒錯。

     其次,在算的過程中,ans是long long 型別的,而a[i]是int型的,算的過程有相乘,數大了就會爆int的,沒有轉換型別,導致WA了一發。。。。

#include<bits/stdc++.h>
using namespace std;
#define mod 998244353
typedef long long ll;
int a[100010];
int main()
{
//   freopen("input.txt","r",stdin);
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; ++i)
        scanf("%d",&a[i]);
    ll ans1=1;
    for(int i=1; i<=n; ++i)
    {
        ans1*=a[i]+1;
        ans1%=mod;
    }
    ll ans2=0;
    for(int i=1; i<=n; ++i)
    {
        ans2+=(ll)(a[i])*(a[i]+1)/2%mod;
        ans2%=mod;
    }
    printf("%lld\n",(ans1+ans2)%mod);
    return 0;
}