跳转至

2020-09-08二分最小生成树

http://icpc.upc.edu.cn/problem.php?cid=2573&pid=4

题目描述

Coco is a beautiful ACMer girl living in a very beautiful mountain. There are many trees and flowers on the mountain, and there are many animals and birds also. Coco like the mountain so much that she now name some letter sequences as Mountain Subsequences.

A Mountain Subsequence is defined as following:

  1. If the length of the subsequence is n, there should be a max value letter, and the subsequence should like this, a1 < ...< ai < ai+1 < Amax > aj > aj+1 > ... > an

  2. It should have at least 3 elements, and in the left of the max value letter there should have at least one element, the same as in the right.

  3. The value of the letter is the ASCII value.

Given a letter sequence, Coco wants to know how many Mountain Subsequences exist.

输入

Input contains multiple test cases.

For each case there is a number n (1<= n <= 100000) which means the length of the letter sequence in the first line, and the next line contains the letter sequence.

Please note that the letter sequence only contain lowercase letters.

输出

For each case please output the number of the mountain subsequences module 2012.

样例输入
4
abca
样例输出
4
提示

The 4 mountain subsequences are:

aba, aca, bca, abca

用标记数组的方法来降低时间复杂度

AC代码

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
char a[100500]= {0};
ull dp2[100500]= {0};
ull dp1[100500]= {0};
ll w[200]={0};
int main()
{
    ll n;
    while(scanf("%lld%s",&n,a+1)!=EOF)
    {
        for(int i=0;i<30;i++)
            w[i]=0;
        for(register ll i=n; i>=1; i--)
        {
            dp2[i]=0;
            for(char j='a'; j<a[i]; j++)
            {
                dp2[i]+=w[j-'a'];
                dp2[i]%=2012;
            }
            w[a[i]-'a']+=dp2[i]+1;
            w[a[i]-'a']%=2012;
        }
        for(int i=0;i<30;i++)
            w[i]=0;
        register long long ans=0;
        for(register ll i=1; i<=n; i++)
        {
            dp1[i]=0;
            for(ll j='a'; j<a[i]; j++)
            {
                dp1[i]+=w[j-'a'];
                dp1[i]%=2012;
            }
            w[a[i]-'a']+=dp1[i]+1;
            w[a[i]-'a']%=2012;
        }
        for(register ll i=1; i<=n; i++)
            ans+=(dp1[i]*dp2[i])%2012,ans%=2012;
        printf("%lld\n",ans);
    }
    return 0;
}
时间超限
#pragma GCC optimize(2)
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
char a[100500]= {0};
ull dp1[100500]= {0};
ull dp2[100500]= {0};
int main()
{
    ll n;
    while(scanf("%lld%s",&n,a+1)!=EOF)
    {
        for(int i=0;i<=n+50;i++)
            dp1[i]=dp2[i]=0;
        for(ll i=1; i<=n; i++)
        {
            for(ll j=1; j<i; j++)
                if(a[j]<a[i])
                    dp1[i]=dp1[i]+dp1[j]+1;
        }
        for(ll i=n; i>=1; i--)
        {
            for(ll j=n; j>i; j--)
                if(a[i]>a[j])
                    dp2[i]=dp2[i]+dp2[j]+1;
        }
        long long ans=0;
        for(ll i=1; i<=n; i++)
        {
            if(dp1[i]>=1&&dp2[i]>=1)
                ans+=dp1[i]%2012*dp2[i]%2012;
            ans%=2012;
        }
        cout<<ans<<endl;
    }
    return 0;
}
http://icpc.upc.edu.cn/problem.php?cid=2570&pid=8

题目描述

In China, there are two companies offering the Internet service for the people from all cities: China Telecom and China Unicom. They both are planning to build cables between cities. Obviously, the government wants to connect all the cities in minimum costs. So the minister of finance Mr. B wants to choose some of the cable plans from the two companies and calculate the minimum cost needed to connect all the cities. Mr. B knows that N-1 cables should be built in order to connect all N cities of China. For some honorable reason, Mr. B should choose K cables from the China Telecom and the rest N-1-K cables from the China Unicom. Your job is to help Mr. B determine which cables should be built and the minimum cost to build them. You may assume that the solution always exists.

输入

Each test case starts with a line containing the number of cities N (1 <= N <= 50,000), number of cable plans M (N-1 <= M <= 100,000) and the number of required cables from China Telecom K (0 <= K <= N-1). This is followed by M lines, each containing four integers a, b, c, x (0 <= a, b <= N-1, a != b, 1 <= c <= 100, x in {0,1} indicating the pair of cities this cable will connect, the cost to build this cable and the company this cable plan belongs to. x=0 denotes that the cable plan belongs to China Telecom and x=1 denotes that the cable plan is from China Unicom.

输出

For each test case, display the case number and the minimum cost of the cable building.

样例输入
2 2 1
0 1 1 1
0 1 2 0
2 2 0
0 1 1 1
0 1 2 0
样例输出
Case 1: 2
Case 2: 1
提示

In the first case, there are two cable plans between the only two cities, one from China Telecom and one from China Unicom. Mr. B needs to choose the one from China Telecom to satisfy the problem requirement even the cost is higher. In the second case, Mr. B must choose the cable from China Unicom, which leads the answer to 1. 二分+最小生成树

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int n,m,k,sum1;
int fa[500500]={0};
struct node
{
    int x,y,z,t;
};
node a[500500]={0};
bool cmp(node a,node b)
{
    if(a.z!=b.z)
        return a.z<b.z;
    else
        return a.t<b.t;
}
int findfa(int x)
{
    if(x==fa[x])
        return x;
    else
        return fa[x]=findfa(fa[x]);
}
int add(int x,int y)
{
    int fx=findfa(x);
    int fy=findfa(y);
    if(fx!=fy)
    {
        fa[fx]=fy;
        return 1;
    }
    return 0;
}
int pd(int x)
{
    for(int i=1;i<=m;i++)
        if(a[i].t==0)
            a[i].z=a[i].z+x;
    for(int i=0;i<=n;i++)
        fa[i]=i;
    sort(a+1,a+m+1,cmp);
    int sum=0,cnt=n-1;
    sum1=0;
    for(int i=1;i<=m;i++)
    {
        if(add(a[i].x,a[i].y))
        {
            sum++;
            cnt-=a[i].t;
            sum1+=a[i].z;
        }
        if(sum==n-1)
            break;
    }
    for(int i=1;i<=m;i++)
    {
        if(a[i].t==0)
        {
            a[i].z=a[i].z-x;
        }
    }
    return cnt>=k;
}
int main()
{
    int summ=0;
    while(scanf("%d%d%d",&n,&m,&k)!=EOF)
    {
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].t);
        }
        int l=-100,r=100;
        while(l<r)
        {
            int mid=(l+r-1)/2;
            if(pd(mid))
            {
                l=mid+1;
                ans=sum1-k*mid;
            }
            else
            {
                r=mid;
            }
        }
        printf("Case %d: %d\n",++summ,ans);
    }
    return 0;
}