2019吉首大学程序设计竞赛

B、干物妹小埋

theme:给定n栋楼的高度及到达该栋楼得到的开心值,开始可以从任一栋楼出发,下一步只会往前到>=它高度的楼,问能获得的最大开心值是多少?(0

solution:就是求最长上升子序列,不过带了权,但数据范围较大,不能用常规DP,考虑用树状数组,每次就是求左边小于 该元素的以此元素结尾的子序列之和的最大值。现将楼高度从小到大排序后去重得到数组v,以排序后的数组的下标作为区间建树,则对于原数组a的每一个元素,找到>=它的第一个下标x,之后在[1,x+1]区间查询最大值,由于是按原顺序先查询后插入的,所以查询时在数组中且下标<=x的都<=a[i]

#include
#define far(i,t,n) for(int i=t;iv;

int main()
{
    int n;
    cin>>n;
    far(i,0,n)
    {
        scanf("%lld",&a[i]);
        v.pk(a[i]);
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    ll ans=0;
    far(i,0,n)
    {
        ll h;
        scanf("%lld",&h);
        int x=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;//树状数组下标从1开始
        ll tmp=query(x);
        ans=max(ans,tmp+h);
       // cout<

*G、说能过那是假的

theme:给定一个只由O、R、Z组成的字符串,问其中子序列ORZ个数

solution:求的子序列很短,o(n)时间即可求出。1' : 用数组r[i]记录每个i位置上为R的后续Z的个数,则从头遍历字符串,记录当前O的个数cnt,则每遇到一个R,ans+=cnt*r[i]

#include
#include
int main()
{
    char ch[100007];
    int len,ans=0;
    scanf("%s",ch);
    len=strlen(ch);
    for(int i=0;i

2' : 数出所有Z的个数cntz,从头遍历一遍字符串,若为O,则cnto++,若为Z则cntz--,若为R,则ans+=cnto*cntz

#include
#include
int main()
{
    char ch[100007];
    int len;
    scanf("%s",ch);
    len=strlen(ch);
    long long cnt1,cnt2;
    cnt1=cnt2=0;
    for (int i = 0; i < len;i++){
        if(ch[i]=='Z') cnt2++;
    }
    long long ans=0;
    for (int i = 0; i < len;i++){
        if(ch[i]=='O') cnt1++;
        if(ch[i]=='Z') cnt2--;
        if(ch[i]=='R') ans+=cnt1*cnt2;
    }
    printf("%lld\n",ans);
}

hdu6536:Hello XTCPC

theme:给定一个字符串,求能形成序列xtCpc个数。1<=n<=2*10^5

solution:从前往。后记录每个相关字符已出现的个数,具体为如果所求序列中它前一个字符已出现的个数>=它才++,最后cnt[c]即为所求

#include 

using namespace std;
int n;
char s[200005];
int cnt[6];
int id(char x){
    if(x == 'x') return 0;
    if(x == 't') return 1;
    if(x == 'C') return 2;
    if(x == 'p') return 3;
    if(x == 'c') return 4;
    return -1;
}
int main()
{
    while(~scanf("%d",&n)){
        scanf("%s",s);
        memset(cnt,0,sizeof cnt);
        for(int i = 0;s[i];i++){
            int tt = id(s[i]);
            if(tt >= 0){
                if(tt == 0) cnt[tt]++;
                else if(cnt[tt-1] > cnt[tt]) cnt[tt]++;
            }
        }
        printf("%d\n",cnt[4]);
    }
    return 0;
}

F、天花乱坠

theme:对于一个正n边形,每次取每条边的终点连接再构造一个n边形,无穷重复下去,问所有n边形的周长之和为多少?最外边边长都为100.

2019吉首大学程序设计竞赛_第1张图片 2019吉首大学程序设计竞赛_第2张图片

solution: 设最外面边长为1,则下一个n边形边长为,所以其实就是以1为首项,为公比的等比数列极限求和为

#include
using namespace std;
#define far(i,t,n) for(int i=t;i>n)
    {
        double angle=pi/n;
        double ans=n*len;
        ans=ans/(1-cos(angle));
        printf("%.2f\n",ans);
    }
}

A、SARS病毒

你可能感兴趣的:(acm,线段树)