2017年沈阳网赛

A题。。
题意:给你一个字符串,问其中出现了k次的子串有多少个。

比赛的时候就感觉是后缀数组,先是题目看错了,以为是大于或等于k次的,然后想出来了和题解差不多的方法,然后lcw好心的提醒了我题目看错了,然后就没想了。。

先求出height数组,从当前i开始扫k个,
区间为【i,i+k-1】如果lcp为3,表示有3个字符串至少出现了k次(比如lcp对应字符串是abc,那三个字符串为a,ab,abc,为什么不考虑bc,c?,因为之后会出现bc为前缀的,c为前缀的),然后需要减去出现k+1次的,区间是【i,i+k】和【i-1,i+k-1】,然后多减去了出现k+2次,加上【i-1,i+k】的lcp就行了,这里注意边界,以及k=1的情况

<当时就是没有想到减去。。>

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <set>


using namespace std;
#define ll long long
const int maxn = 1e5+10;

int vis[maxn],q[maxn];
char str[maxn];
struct Suffix
{
    int s[maxn];
    int SA[maxn],ranked[maxn],height[maxn];
    int x[maxn],y[maxn],buc[maxn],len,m;
    void init(char *str)
    {
        memset(SA,0,sizeof(SA));
        memset(s,0,sizeof(s));
        memset(ranked,0,sizeof(ranked));
        memset(height,0,sizeof(height));
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));
        memset(buc,0,sizeof(buc));
        len=strlen(str);
        for(int i=0;i<len;i++) s[i]=str[i]-'a'+1;
        m=35;//
    }
    void GetSA()
    {
        for (int i = 0; i < m; i++)
            buc[i] = 0; // buc 是一个桶
        for (int i = 0; i < len; i++) buc[x[i] = s[i]]++;
        for (int i = 1; i < m; i++)
             buc[i] += buc[i - 1];
        for (int i = len - 1; i >= 0; i--)
            SA[--buc[x[i]]] = i;
        for (int k = 1; k <= len; k <<= 1) { // k 倍增
          int p = 0;
          //对第二关键字排序,y[i]:第i大的第二关键字是谁
          // 后缀 len - k 及之后的所有后缀第二关键字最小。为0
          for (int i = len - 1; i >= len - k; i--)
            y[p++] = i;
          for (int i = 0; i < len; i++)
                if (SA[i] >= k)
                    y[p++] = SA[i] - k;
         //总体来排个序,求出SA
          for (int i = 0; i < m; i++) buc[i] = 0;
          for (int i = 0; i < len; i++)
                buc[x[y[i]]]++;
          for (int i = 1; i < m; i++)
                buc[i] += buc[i - 1];
          for (int i = len - 1; i >= 0; i--)
                SA[--buc[x[y[i]]]] = y[i];
          swap(x, y);
          p = 1; x[SA[0]] = 0;
          // 重新计算每个一元的名次。则x数组里存的是总体的顺序
          for (int i = 1; i < len; i++) {
            if (y[SA[i - 1]] == y[SA[i]] && y[SA[i - 1] + k] == y[SA[i] + k])
              x[SA[i]] = p - 1;
            else x[SA[i]] = p++;
          }
          if (p >= len) break; // 每个后缀的名次已经完全不同,不需要继续倍增
              m = p; // 更新名次的最大值。
        }
    }
    void Getheight()
    {
        for(int i=0;i<len;i++)
            ranked[SA[i]]=i;
        int k=0;
        for(int i=0;i<len;i++)
        {
            if(ranked[i]==0) {height[0]=0;continue;}
            if(k) k--;
            int j=SA[ranked[i]-1];
            while(s[i+k]==s[j+k]&&i+k<len&&j+k<len) k++;
            height[ranked[i]]=k;
        }
    }
};
Suffix SS;
int dp[maxn][20];
void RMQ(int len)
{
    for(int i=1;i<len;i++) dp[i][0]=SS.height[i];
    for(int i=1;(1<<i)<=len;i++)
    {
        for(int j=1;j+(1<<i)-1<=len;j++)
        {
            dp[j][i]=min(dp[j][i-1],dp[j+(1<<(i-1))][i-1]);
        }
    }
}
int len;
int ass(int i,int j)
{
    if(i<0) return 0;
    if(j>=len) return 0;
    if(i==j) return len-SS.SA[i];
    int k=0;
    i++;
    while((1<<(k+1))<=j-i+1) k++;
    if(k==0) return dp[i][k];
    return min(dp[i][k],dp[j-(1<<k)+1][k]);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(dp,0,sizeof(dp));
        int k;
        scanf("%d",&k);
        scanf("%s",str);
        SS.init(str);
        SS.GetSA();
        SS.Getheight();
        len=strlen(str);
        RMQ(len);
        ll ans=0;
        for(int i=0;i+k-1<len;i++)
        {
            int t1=ass(i,i+k-1);
            int t2=-ass(i,i+k);
            int t3=-ass(i-1,i+k-1);
            int t4=ass(i-1,i+k);
            ans+=t1+t2+t3+t4;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

B题:ans=k+(m-k)*k
D题:dp
E题:ans=F(2k+3)-1
F(1)+F(2)+…+F[n]=F[n+2]-1;

F题:gems gems gems

题意:给n张牌,每张牌都有一个值,A和B轮流从左往右取牌,前一个人取了k张,后一个人只能取k或者k+1张。A先取,第一次只能取1或者2张。A要是他们的差值尽可能大,B要使他们的差值尽可能地小

woc,这个题怎么又理解错了题意:(
(比赛中) 从左往右取理解成了,A,B在取牌的时候,要求取的牌的下标是从左往右连续的,A和B开始取牌的位子不定。。比如1,2,10,4 ; (我理解的最佳方案是)A取2,10,则B就不能取了。。。如果是我理解的这样的话,是不是贼复杂,这么复杂肯定不是dp。。博弈的话,必胜必败状态又找不出来==

忘掉之前xiaoshuo的
我们来看看这个题的正确打开方式
从左往右取,比如1,2,3,4,5 A取了1,2,B只能从3开始取2张或者3张

解法:dp。

dp[i][j][k]:第i个人,从第j张开始取,前一轮取了k张
i=0,表示A
i=1,表示B
sum:表示前缀和
状态转移:
dp[0][j][k]=max(dp[1][j+k][k],dp[1][j+k+1][k+1]+sum[j+k])+sum[j+k-1]-sum[j-1];

dp[1][j][k]=min(dp[0][j+k][k],dp[1][j+k+1][k+1]-sum[i+j])-sum[j+k-1]+sum[j-1];
因为这道题的空间比较小,int数组大概只能开到1e6;
首先k,1+2+….+k<=n,所以k不超过200;对当前第j个数,最多只会受到j+k+1的影响。用滚动数组。滚动数组还只能用&,如果用%会超时==,用&的话,inf就取255,这样&起来就和%一样的意思了

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdio>

using namespace std;
const int maxn = 20005;
#define inf 255
int sum[maxn];
int dp[2][260][210];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(sum,0,sizeof(sum));
        int n,a;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a);
            sum[i]=sum[i-1]+a;
        }
        int maxk=(int)sqrt(2*n)+1;
        memset(dp,0,sizeof(dp));
        for(int i=n;i>=1;i--)
        {
            for(int k=1;k<=maxk&&k+i-1<=n;k++)
            {
                dp[0][i&inf][k]=dp[1][(i+k)&inf][k]+sum[i+k-1]-sum[i-1];
                cout<<dp[0][i&inf][k]<<endl;
                dp[1][i&inf][k]=dp[0][(i+k)&inf][k]+sum[i-1]-sum[i+k-1];
                cout<<dp[1][i&inf][k]<<endl;
                if(i+k<=n)
                {
                    dp[0][i&inf][k]=max(dp[0][i&inf][k],dp[1][(i+k+1)&inf][k+1]+sum[i+k]-sum[i-1]);
                    cout<<dp[0][i&inf][k]<<endl;
                    dp[1][i&inf][k]=min(dp[1][i&inf][k],dp[0][(i+k+1)&inf][k+1]+sum[i-1]-sum[i+k]);
                    cout<<dp[1][i&inf][k]<<endl;
                }
            }
        }
        printf("%d\n",dp[0][1][1]);
    }
    return 0;
}

H题:transaction transaction transaction
队友过的。。我还没补。。据说学长直接dfs出来了?

J:ping ping ping
当时队友用树剖怼,果断超时。
首先想到LCA吧。。
lca按深度从大到小排个序,然后对于当前的lca,我们看它所在的那条路径上有没有被破坏掉的点,如果没有就去掉当前lca.
关于如何确定有没有被破坏的点,要么就是从两点往上走,看有没有经过被破坏掉的点。要么从当前lca往所有子树标记,如果子树被标记了,则不用继续标记,最后看u,v两点有没有被标记。要么从两点往根找,一直到找到自己的lca,如果中途没找到了已经被破坏掉的lca,则去掉当前lca。

L:题目看懂了,模拟一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值