补题日记(持续更新)

52 篇文章 1 订阅
34 篇文章 0 订阅

第一天:
牛客多校第五场D Double Strings
链接:牛客第五次double strings
给定两个字符串A,B求长度相同的AB子串,使得子串的前面部分相等,且第一个不相等的位置B>A。求这样的子串个数。
思路:f[i][j]表示A的前i个字符与B的前j个字符能组成多少相等的子串。
自我理解:
比如说abcd,abdc,那样遍历到b的时候由于前面a是一样的,那当前的字串数量f[i][j]就会加上前面的字串数量+f[i-1][j-1],(也就是加上a时的数量),其他情况下就是加上大一点的那个,f[i][j]=((f[i-1][j]+f[i][j-1])%mod-f[i-1][j-1]+mod)%mod;比如说f[i-1][j]=5,f[i][j-1]=6,f[i-1][j-1]是两者重合的部分,那f[i][j]就会是大一点的那个(我猜的hhh)
AC代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
char a[5005],b[5005];
int dp[5005][5005],f[5005][5005];
ll res=0;
const int mod=1e9+7;
int main(){
    scanf("%s%s",a+1,b+1);
    int n=strlen(a+1),m=strlen(b+1);
    memset(f,0,sizeof(f));
    f[0][0]=1;
    for (int i=1; i<=m; i++) f[0][i]=1;
    for (int i=1; i<=n; i++) f[i][0]=1;
    for (int i=1; i<=n; i++){
        for (int j=1; j<=m; j++){
            f[i][j]=((f[i-1][j]+f[i][j-1])%mod-f[i-1][j-1]+mod)%mod;
            if (a[i]==b[j]){
            f[i][j]=(f[i-1][j-1]+f[i][j])%mod;
            }  
        }
    }
    for (int i=1; i<=n; i++){
        for (int j=1; j<=m; j++){
            dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
            if (a[i]<b[j]) dp[i][j]=(dp[i][j]+f[i-1][j-1])%mod;
        }
    }
    printf("%lld",dp[n][m]);
    return 0;
}

Rise in Price(杭电多校DP):
链接:Rise in Price
题意:从(1,1)走到(n,n),只能向下或者向右走,输入a数组(nn),然后输入b数组(nn),每个格子都有a和b,表示有a个钻石,可以让单价上涨b.
思路:dp[i][j][k]表示到达ij时所持有的宝石为k的时候可以卖的价钱,不难想到设两个状态f[i][j][x]和f[i][j][y],当x<y时,若f[i][j][x]<f[i][j][y]时,前者不可能是最优解,数量少且单价低的一定不是最优解,故剔除,剩下的可能的最优解与i,j上的a,b构成i,j位置上的最优解

在这里插入图片描述

官方题解:在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;

const int N = 105;
typedef pair<long long, long long> PII;
typedef vector<PII> V;
typedef long long ll;

vector<PII> p[N][N];
PII tem[N * N * N];    //临时序列
int topz = 0;
ll a[N][N], b[N][N];

void check(PII x) {
    while(topz && tem[topz].second <= x.second) topz --; //序列中的所有的first都要小于x的first,因为是first按升序排的,
                                                        //这句话也保证了序列中的second从大到小
    if(topz == 0 || tem[topz].first < x.first) tem[++ topz] = x; //当x的first == 序列中的某个可能最优解的first的同时,  
                                                                //x的second一定小于这个可能最优解的second,也就是说是一个非最优解
}

void merge(const V &x, const V &y, V &z) {
    int sx = x.size(), sy = y.size();
    int topx = 0, topy = 0;
    topz = 0;

    while(topx < sx && topy < sy) 
        check((x[topx].first < y[topy].first) ? x[topx ++] : y[topy ++]); //转移过来的可能最优解也是按first升序排列的
    while(topx < sx) check(x[topx ++]);
    while(topy < sy) check(y[topy ++]);

    for(int i = 1; i <= topz; ++ i) z.push_back(tem[i]); //将筛完之后的可能最优解按宝石数量升序放入下一个状态中
}

void solve() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i)  
        for(int j = 1; j <= n; ++ j) 
            scanf("%lld", &a[i][j]),  p[i][j].clear();;
    for(int i = 1; i <= n; ++ i)
        for(int j = 1; j <= n; ++ j)
            scanf("%lld", &b[i][j]);
    
    p[1][1].push_back(make_pair(a[1][1], b[1][1]));

    for(int i = 1; i <= n; ++ i) 
        for(int j = 1; j <= n; ++ j) {
            if(i == 1 && j == 1) continue;
            else if(i == 1) 
                p[i][j].push_back(p[i][j - 1][0]);//第一行和第一列的转移都之由一种情况
            else if(j == 1) 
                p[i][j].push_back(p[i - 1][j][0]);
            else 
                merge(p[i - 1][j], p[i][j - 1], p[i][j]);
            for(int k = 0; k < p[i][j].size(); ++ k) p[i][j][k].first += a[i][j], p[i][j][k].second += b[i][j];
        }

    ll MAX = 0;

    for(int i = 0; i < p[n][n].size(); ++ i) {
        MAX = max(MAX, p[n][n][i].first * p[n][n][i].second); //从所有没有被提出的可能最优解当中选出真正的最优解
    }

    printf("%lld\n", MAX);
}

int main() {
    int t;
    scanf("%d", &t);
    while(t --) {
        solve();
    }
    return 0;
}

牛客第五场 K-King of Range
ST表+双指针

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<queue>
using namespace std;
#define ll long long
#define N 100005
 
int stmax[N][20],stmin[N][20],mn[N];
int a[N];
 
int t,q,n;
int x,y;
 
void init()
{
    mn[0]=-1;
    for (int i=1;i<=n;i++)
    {
        mn[i]=((i & (i-1))==0) ? mn[i-1]+1 : mn[i-1];
        stmax[i][0]=stmin[i][0]=a[i];
    }
    for (int j=1;j<=mn[n];j++)
        for (int i=1;i+(1<<j)-1<=n;i++)
        {
            stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);
            stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);
        }
}
 
int rmq_max(int L,int R)
{
    int k=mn[R-L+1];
    return max(stmax[L][k],stmax[R-(1<<k)+1][k]);
}
 
int rmq_min(int L,int R)
{
    int k=mn[R-L+1];
    return min(stmin[L][k],stmin[R-(1<<k)+1][k]);
}

int main()
{
        scanf("%d",&n);
        scanf("%d",&q);
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        init();
        while(q--){
        int k;
        scanf("%d",&k);
        int cnt=0,l=0;
        ll ans=0;
		for(int i=2;i<=n;i++){
			while(l<i&&rmq_max(l+1,i)-rmq_min(l+1,i)>k){
				l++;
			}
			ans+=l;
		} 
		printf("%lld\n",ans);	
		}
    return 0;
}

杭电第八场
我的题解链接:T_T
AC代码:

#include<iostream>
#define LL long long
using namespace std;

const LL mod = 998244353;
const int N = 100005;
LL a1[N], a2[N];
int T, n, q;

LL lowbit(LL x) { return x & (-x); }

struct SegmentTree1 {
LL l, r, sum1, sum2, la, tg;
#define ls x<<1
#define rs x<<1|1
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum1(x) tree[x].sum1
#define sum2(x) tree[x].sum2
#define la(x) tree[x].la
#define tg(x) tree[x].tg 
}tree[N << 2];

//向上是线段树合并 
void pushup(int x) {
	sum1(x) = (sum1(ls) + sum1(rs)) % mod;
	sum2(x) = (sum2(ls) + sum2(rs)) % mod;
	tg(x) = tg(ls) & tg(rs);//如果两个区间都是1的话就不继续递归下去了 
}

void pushdown(int x) {
	la(ls) = la(ls) * la(x) % mod;
	la(rs) = la(rs) * la(x) % mod;
	sum1(ls) = sum1(ls) * la(x) % mod;
	sum1(rs) = sum1(rs) * la(x) % mod;
	tg(ls) |= tg(x);
	tg(rs) |= tg(x);
	if (tg(ls))sum2(ls) = 0;
	if (tg(rs))sum2(rs) = 0;
	la(x) = 1;//标记 
}

void build(int x,int l,int r) {
	la(x) = 1, tg(x) = 0;
	l(x)=l,r(x)=r;
	if (l(x) == r(x)) {
		sum1(x) = a1[l(x)], sum2(x) = a2[l(x)];
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	pushup(x);
}

LL query(int x, int l, int r) {
	if (l <= l(x) && r >= r(x)) {
		return (sum1(x) + sum2(x)) % mod;
	}
	pushdown(x);
	int mid = (l(x) + r(x)) >> 1;
	LL ans = 0;
	if (l <= mid)ans += query(ls, l, r);
	if (r > mid)ans += query(rs, l, r);
	ans%=mod;
	return ans;
}

void up1(int x, int l, int r) {
	if (l(x) == r(x)) {
		if (sum2(x)) {
			sum2(x) -= lowbit(sum2(x));
		}
		else {
			sum1(x) = 0;
			tg(x) = 1;
		}
		return;
	}
	pushdown(x);
	int mid = (l(x) + r(x)) >> 1;
	if (l <= mid && !tg(ls))up1(ls, l, r);
	if (r > mid && !tg(rs))up1(rs, l, r);
	pushup(x);
}

void up2(int x, int l, int r) {
	if (l <= l(x) && r >= r(x)) {
		sum1(x) = sum1(x) * 2 % mod;
		la(x) = la(x) * 2 % mod;
		return;
	}
	pushdown(x);
	int mid = (l(x) + r(x)) >> 1;
	if (l <= mid)up2(ls, l, r);
	if (r > mid)up2(rs, l, r);
	pushup(x);
}

int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) {
			LL x;
			scanf("%lld", &x);
			for (int k = 30; k >= 0; k--) {
				if ((1ll << k) <= x) {
					a1[i] = (1ll << k);
					a2[i] = x - a1[i];
					break;
				}
			}
		}
		build(1,1,n);
		scanf("%d", &q);
		while (q--) {
			int opt, l, r;
			scanf("%d%d%d", &opt, &l, &r);
			if (opt == 1) {
				printf("%lld\n", query(1, l, r));
			}
			else if (opt == 2) {
				up1(1, l, r);
			}
			else if (opt == 3) {
				up2(1, l, r);
			}
		}
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值