第十九届浙大城市学院程序设计竞赛

第十九届浙大城市学院程序设计竞赛

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;
}
posted @ 2022-04-12 13:08  lmj_1  阅读(104)  评论(0)    收藏  举报