1. 程式人生 > 其它 >第十九屆浙大城市學院程式設計競賽

第十九屆浙大城市學院程式設計競賽

第十九屆浙大城市學院程式設計競賽

E Disjoint Path On Tree

題意:求樹上不相交簡單路徑對的數量
做法:其實很容易想到,我們需要求f1[x]表示經過x點的子樹內的簡單路徑數,f2[x]表示子樹x的內的簡單路徑數量,但是統計數量的時候賽時我想的複雜了一些,因為還需要換根求一下各種值,但其實我們發現m個點構成的子樹內簡單路徑數量就是其中數對的數量m*(m+1)/2,因為任意兩點都存在簡單路徑,那麼計算方法就簡單了,就等於\(f1[x]*m(m+1)/2\),m=n-f3[x],f3[x]表示x子樹大小,但是我們考慮這樣計算,其實每個子樹的各個兒子之間的數量都被重複計算了,我們需要剪掉這部分,也就是剪掉f2[v]的,v是x的子節點

點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;

const int maxn=2e5+10;

typedef long long ll;
vector<int>G[maxn];
ll f1[maxn],f2[maxn],f3[maxn],dp[maxn];
const ll mod=1e9+7;
ll ans=0;
int n;

void init(int n){
    for (int i=1;i<=n;i++) G[i].clear(),dp[i]=f1[i]=f2[i]=f3[i]=0;
}

ll quickpow(ll a,ll b){
    ll p=1;
    for (;b;b>>=1){
        if(b&1ll) p=p*a%mod;
        a=a*a%mod;
    }
    return p%mod;
}

void dfs(int x,int f){
    f3[x]=f1[x]=1;
    for (int i=0;i<G[x].size();i++){
        int v=G[x][i];
        if(v==f) continue;
        dfs(v,x);
        dp[x]=(dp[x]-f2[x]*f2[v])%mod;
        f1[x]=(f1[x]+f3[x]*f3[v]%mod)%mod;
        f3[x]=(f3[x]+f3[v])%mod;
        f2[x]=(f2[x]+f2[v])%mod;
    }
    f2[x]=(f2[x]+f1[x])%mod;
    ll p=(n-f3[x]+mod)%mod;
    ll m=p*(p+1ll)%mod*quickpow(2,mod-2)%mod;
    dp[x]=(dp[x]+f1[x]*m)%mod;
    ans=((ans+dp[x])%mod+mod)%mod;
}

int main(){
    #ifdef lmj_debug
        freopen("1.in","r",stdin);
    #endif
    int T;
    cin>>T;
    while(T--){
       ans=0;
       scanf("%d",&n);
       if(n==1 || n==2) {
           if(n==1) printf("0\n");
           else {
               int x,y;
               cin>>x>>y;
               printf("1\n");
           }
           continue;
       }
       init(n);
       for (int i=1;i<n;i++){
           int u,v;
           scanf("%d%d",&u,&v);
           G[u].push_back(v);
           G[v].push_back(u);
       }
       dfs(1,1);
       //for (int i=1;i<=n;i++) printf("%lld ",f2[i]);
       printf("%lld\n",ans);
    }
    return 0;
}

H Distance

題意:給定多個線段,要求一箇中間點,使得到各個線段的距離都最短
做法:其實們就是選一箇中點即可,因為中點的性質就是到一條線段上其它點的和最小,所以我們只需要對頂堆維護中點值即可,現在我們來考慮怎麼計算距離之和,1.對於一個線段,如果其值位於現在中點的兩邊,那麼答案貢獻不增加。2.對於一條線段右端點r<中點,那麼中點的值會改變,但是我們思考中點移動會改變當前的嗎?在中點移動後並未使左右線段數量改變的前提下其實答案不會變,所以我們只需要考慮新加進來的點產生的貢獻,貢獻即為中點值top-r。3.對於l大於中點也是類似的加入貢獻即可

點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

priority_queue<int,vector<int>,less<int> >Q1;
priority_queue<int,vector<int>,greater<int> >Q2;

int main(){
    #ifdef lmj_debug
        freopen("1.in","r",stdin);
    #endif
    int n;
    ll ans=0;
    cin>>n;
    Q1.push(-1e9-10);
    Q2.push(1e9+10);
    for (int i=1;i<=n;i++){
        int l,r;
        scanf("%d%d",&l,&r);
        if(r<Q1.top()){
            ans+=(Q1.top()-r);
            Q2.push(Q1.top());
            Q1.pop();
            Q1.push(l);
            Q1.push(r);
        }else if(l>Q2.top()){
            ans+=(l-Q2.top());
            Q1.push(Q2.top());
            Q2.pop();
            Q2.push(l);
            Q2.push(r);
        }else Q1.push(l),Q2.push(r);
        printf("%lld\n",ans);
    }
    return 0;
}

J Substring Inversion (Easy Version)

做法:其實比較簡單就是直接暴力處理出所有字串然後排序,\(n^3logn\),考慮到a<c所以我們做匹配的時候直接\(n^3\)做,具體見程式碼

點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const ll mod=1e9+7;

int sum[550];
vector< pair<string,int> >a;

int main(){
    #ifdef lmj_debug
        freopen("1.in","r",stdin);
    #endif
    int T;
    cin>>T;
    while(T--){
        a.clear();
        int n;
        string s;
        cin>>n>>s;
        for (int i=0;i<n;i++){
            sum[i]=0;
            string ch="";
            for (int j=i;j<n;j++){
                ch+=s[j];
                a.push_back(make_pair(ch,i));
            }
        }
        long long ans=0;
        sort(a.begin(),a.end());
        for (int i=0;i<a.size();i++){
            int r=a[i].second;
            for (int j=r+1;j<n;j++){
                ans+=sum[j];
            }
            sum[r]++;
        }
        printf("%lld\n",ans%mod);
    }
    return 0;
}

字尾陣列做法:


F Sum of Numerators

做法:其實很簡單,但是當時還是想了一小會兒,我們直接通過2^x冪去篩就行了,然後x要小於k,因為x-1篩出來的必定含有x的,所以還要將x篩出來的方案減一下就ok了

點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

ll phi[40];

int main(){
    #ifdef lmj_debug
        freopen("1.in","r",stdin);
    #endif
    for (int i=0;i<=32;i++) phi[i]=(1ll<<i);
    int T;
    cin>>T;
    while(T--){
        ll n,k;
        scanf("%lld%lld",&n,&k);
        ll ans=0;
        ll p=n/2ll;
        if(n&1ll) p++;
        ans+=((p)+(p*(p-1)));
        if(k>32) k=32;
        ll last=0;
        for (int i=k;i>=1;i--){
            ll x=n/phi[i];
            ll o=(x+(x*(x-1)/2));
            ans+=o;
            ans-=last;
            last=o*2ll;
        }
        
        if(k==0) {
            p=n/2ll;
            ans+=((2ll*p)+(p*(p-1)));
        }
        printf("%lld\n",ans);
    }
    return 0;
}