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


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

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 
using namespace std;

const int maxn=2e5+10;

typedef long long ll;
vectorG[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>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

H Distance

题意:给定多个线段,要求一个中间点,使得到各个线段的距离都最短
做法:其实们就是选一个中点即可,因为中点的性质就是到一条线段上其它点的和最小,所以我们只需要对顶堆维护中点值即可,现在我们来考虑怎么计算距离之和,1.对于一个线段,如果其值位于现在中点的两边,那么答案贡献不增加。2.对于一条线段右端点r<中点,那么中点的值会改变,但是我们思考中点移动会改变当前的吗?在中点移动后并未使左右线段数量改变的前提下其实答案不会变,所以我们只需要考虑新加进来的点产生的贡献,贡献即为中点值top-r。3.对于l大于中点也是类似的加入贡献即可

点击查看代码
#include 
using namespace std;

typedef long long ll;

priority_queue,less >Q1;
priority_queue,greater >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(rQ2.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\(n^3\)做,具体见代码

点击查看代码
#include 
using namespace std;

typedef long long ll;

const ll mod=1e9+7;

int sum[550];
vector< pair >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

后缀数组做法:


F Sum of Numerators

做法:其实很简单,但是当时还是想了一小会儿,我们直接通过2^x幂去筛就行了,然后x要小于k,因为x-1筛出来的必定含有x的,所以还要将x筛出来的方案减一下就ok了

点击查看代码
#include 
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<>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;
}