【过题记录】7.20

前两题一直在打模拟赛,有点忙,就没更

Red Playing Cards

在这里插入图片描述

算法:动态规划

其实这就是一个线段覆盖问题,只不过大线段能够包含小线段。
这就启发我们,对于每个大线段分别跑一个dp,合并在他内部的小线段。而后对于每一个大线段,再跑一个总的dp即可。

也可以只跑一遍dp,有一个小trick,在线段两端添0,这样答案就等同于f[0]

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

#define int long long

const int N = 6e3+100;
int n;
int f[N];
int l[N],r[N];
int a[N];

struct Node{
	int l,r,x;
}b[N];

int g[N];
int dp[N];

bool cmp(Node x,Node y){
	int l1 = x.r-x.l+1;
	int l2 = y.r-y.l+1;
	return l1 < l2;
}

signed main(){
	cin>>n;
	for (int i = 1; i <= 2*n; i++){
		cin>>a[i];
		if (l[a[i]] == 0) l[a[i]] = i;
		else r[a[i]] = i;
	}
	for (int i = 1; i <= n; i++)
	  b[i] = {l[i],r[i],i};
	sort(b+1,b+n+1,cmp);
	for (int i = 1; i <= n; i++){
		int x = b[i].x;
		for (int j = 1; j <= 2*n; j++) g[j] = 0;
		for (int j = b[i].l; j <= b[i].r; j++){
			g[j] = g[j-1]+x;
			if (l[a[j]] < j && l[a[j]] > b[i].l)
			  g[j] = max(g[l[a[j]]-1]+f[a[j]],g[j]);
		}
		f[x] = g[b[i].r];
	}
	for (int i = 1; i <= 2*n; i++){
		dp[i] = max(dp[i-1],dp[i]);
		if (l[a[i]] == i) continue;
		dp[i] = max(dp[i],dp[l[a[i]]-1]+f[a[i]]);
	}
	cout<<dp[2*n];
	return 0;
}

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

#define int long long

const int N = 6e3+100;
int n;
int f[N];
int l[N],r[N];
int a[N];

struct Node{
	int l,r,x;
}b[N];

int g[N];
int dp[N];

bool cmp(Node x,Node y){
	int l1 = x.r-x.l+1;
	int l2 = y.r-y.l+1;
	return l1 < l2;
}

signed main(){
	cin>>n;
	for (int i = 2; i <= 2*n+1; i++){
		cin>>a[i];
		if (l[a[i]] == 0) l[a[i]] = i;
		else r[a[i]] = i;
	}
	for (int i = 1; i <= n; i++)
	  b[i] = {l[i],r[i],i};
	b[n+1] = {1,2*n+2,0}; ++n;
	sort(b+1,b+n+1,cmp);
	for (int i = 1; i <= n; i++){
		int x = b[i].x;
		for (int j = 0; j <= 2*n; j++) g[j] = 0;
		for (int j = b[i].l; j <= b[i].r; j++){
			g[j] = g[j-1]+x;
			if (l[a[j]] < j && l[a[j]] > b[i].l)
			  g[j] = max(g[l[a[j]]-1]+f[a[j]],g[j]);
		}
		f[x] = g[b[i].r];
	}
	cout<<f[0];
//	for (int i = 1; i <= 2*n; i++){
//		dp[i] = max(dp[i-1],dp[i]);
//		if (l[a[i]] == i) continue;
//		dp[i] = max(dp[i],dp[l[a[i]]-1]+f[a[i]]);
//	}
//	cout<<dp[2*n];
//	for (int i = 1; i <= n; i++) cout<<"i = "<<f[i]<<endl;
	return 0;
}

Lucky Common Subsequence

在这里插入图片描述

算法:KMPdp

这题只是一个加强版的LCS,只不过多了一个子串的限定。
所以我们不难想到状态设置:
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示第一个串从1……i,第二个串从2……j,匹配了第三个串k个长度的最长LCS
关键就是第三维状态的转移,我们不能随便转移,而是利用KMP的NEXT数组进行转移
在第三个串的k位之后加入s[i],利用NEXT数组转移到相应的位置进行转移。
由于本题要求输出路径,有两种方法
第一种就是常规的求最长长度,而后利用状态关系倒序递归输出。
第二种就是直接用string去存储答案。
这里用的第二种方法

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

const int N = 1e2+10;
string f[N][N][N];
int n,m,q;
char s1[N],s2[N],s3[N];
int Ne[N];

void KMP(){
	Ne[1] = 0;
	int j = 0;
	for (int i = 2; i <= q; i++){
		while (j > 0 && s3[i]!=s3[j+1]) j=Ne[j];
		if (s3[i] == s3[j+1]) j++;
		Ne[i] = j;
	}
}

void Com(string &a,string b){
	if (a.size() < b.size()) a = b;
}

int main(){
	cin>>(s1+1); cin>>(s2+1); cin>>(s3+1);
	n = strlen(s1+1); m = strlen(s2+1); q = strlen(s3+1);
	KMP();
	for (int i = 1; i <= n; i++){
		for (int j = 1; j <= m; j++){
			for (int k = 0; k < q; k++){
				Com(f[i][j][k],f[i-1][j][k]);
				Com(f[i][j][k],f[i][j-1][k]);
				if (s1[i]!=s2[j]) continue;
				int now = k;
				while (now && s1[i]!=s3[now+1]) now = Ne[now];
				if (s1[i] == s3[now+1]) now++;
				Com(f[i][j][now],f[i-1][j-1][k]+s1[i]);
			}
		}
	}
	string ans = "";
	for (int i = 0; i < q; i++)
	  Com(ans,f[n][m][i]);
	if (ans.size() == 0) cout<<0; else cout<<ans;
	return 0;
}

算是一个比较典的KMPdp的题目


启发式合并
具体的等一下再说

#include<iostream>
#include<vector>
using namespace std;

#define ull unsigned long long
#define ll long long

const int N = 5e5+100;
const int M = 1e6+100;
typedef pair < ll , ll > pii;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
vector < int > a[N];
int n;
ll v[N];
int son[N];
ll s1[N],s2[N],sz[N];
//s1 he s2 pingfang

void Dfs(int x,int faa){
	for (int i = 0; i < a[x].size(); i++){
		int y = a[x][i];
		if (y == faa) continue;
		Dfs(y,x);
		if (sz[y] > sz[son[x]]) son[x] = y;
		s1[x]+=s1[y]; s2[x]+=s2[y]; sz[x]+=sz[y];
	}
	sz[x]++;
	s1[x]+=v[x];
	s2[x]+=(v[x]*v[x]);
	return;
}

ll ans[N];

ll vl[M],num[M];
#define lowbit(x) (x&(-x))
void Change(int x,ll x1,ll x2){
	for (int i = x; i < M; i+=lowbit(i))
	  vl[i]+=x1 , num[i]+=x2;
}

pii Ask(int x){
	ll x1 = 0 , x2 = 0;
	for (int i = x; i; i-=(i&(-i)))
	  x1+=vl[i],x2+=num[i];
	return mp(x1,x2);
}

void Calc(int x,int faa,vector < ll >& now, ll &an){
	now.pb(v[x]);
	pii l = Ask(v[x]) , r = Ask(M-1);
	an+=(l.se*v[x]*v[x]-l.fi)+((r.fi-l.fi)-(r.se-l.se)*v[x]*v[x]);
	for (int i = 0; i < a[x].size(); i++){
		int y = a[x][i]; if (y == faa) continue;
		Calc(y,x,now,an);
	}
	return;
}

void Del(int x,int faa){
	Change(v[x],-v[x]*v[x],-1);
	for (int i = 0; i < a[x].size(); i++){
		int y = a[x][i]; if (y == faa) continue;
		Del(y,x);
	}
}

void Dsu(int x,int faa,int op){
	int so = son[x];
	for (int i = 0; i < a[x].size(); i++){
		int y = a[x][i];
		if (y == faa || y == so) continue;
		Dsu(y,x,0);
		ans[x]+=ans[y];
	}
	if (so){
//		cout<<"OK";
		Dsu(so,x,1);
		ans[x]+=ans[so];
	}
	// 接下来计算子树之间的贡献
	for (int i = 0; i < a[x].size(); i++){
		int y = a[x][i]; if (y == faa || y == so) continue;
		vector < ll > now;
		Calc(y,x,now,ans[x]);
		for (int j = 0; j < now.size(); j++) Change(now[j],now[j]*now[j],1);
	}
	pii l = Ask(v[x]) , r = Ask(M-1);
	ans[x]+=(l.se*v[x]*v[x]-l.fi)+((r.fi-l.fi)-(r.se-l.se)*v[x]*v[x]);
	Change(v[x],v[x]*v[x],1);
	if (op == 0) Del(x,faa);
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
	cin>>n;
	for (int i = 1,x,y; i < n; i++)
	  cin>>x>>y,a[x].pb(y),a[y].pb(x);
	for (int i = 1; i <= n; i++) cin>>v[i];
	Dfs(1,0);
    Dsu(1,0,0);
    ull An = 0;
    for (int i = 1; i <= n; i++){
    	ull x = sz[i]*s2[i],y = s1[i]*s1[i];
    	x = x+ans[i];
    	x = (x-y);
    	An^=x;
	}
	cout<<An<<endl;
	return 0;
}

Ciel and Duel

贪心

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

#define int long long

const int N = 500;
int n,m;
int at[N],de[N];
int a[N];
int n1,n2;

int Do1(){
	int ans = 0;
	int now = m;
	for (int i = 1; i <= n1; i++){
		if (now == 0) break;
		if (a[now] >= at[i]) ans+=(a[now]-at[i]),now--;
		else break;
	}
	return ans;
}

bool vi[N];
int b[N],cnt=0;

int Do2(){
	int now = 1;
	for (int i = 1; i <= n2; i++){
		while (now <= m && a[now] <= de[i]) now++;
		vi[now] = 1; now++;
	}
	if (now > m) return 0;
	for (int i = 1; i <= m; i++) if (vi[i] == 0) b[++cnt] = a[i];
	now = 1;
	int ans = 0;
	bool f = 1;
	memset(vi,0,sizeof vi);
	for (int i = 1; i <= n1; i++){
		while (now <= cnt && b[now] < at[i]) now++;
		if (now > cnt) return ans;
		ans+=(b[now]-at[i]);
		vi[now++] = 1;
	}
	for (int i = 1; i <= cnt; i++) if (vi[i] == 0) ans+=b[i];
	return ans;
}

signed main(){
	cin>>n>>m;
	memset(de,-1,sizeof de); memset(at,-1,sizeof at);
	memset(a,-1,sizeof a); memset(b,-1,sizeof b);
	for (int i = 1; i <= n; i++){
		string s; int x;
		cin>>s>>x;
		if (s == "ATK") at[++n1] = x;
		else de[++n2] = x;
	}
	for (int i = 1; i <= m; i++) cin>>a[i];
	sort(at+1,at+n1+1); sort(de+1,de+n2+1);sort(a+1,a+m+1);
	int Max = max(Do1(),Do2());
	cout<<Max<<endl;
	return 0;
}
表名 表标题(沐数) 字段序号 字段名称 字段标题(沐数) e_customer 客户信息表 1 CUSTOMID 客户ID e_customer 客户信息表 2 CUSTOMNAME 客户姓名 e_customer 客户信息表 3 COUNTRY 国家 e_customer 客户信息表 4 IS_DELETED 数据删除标签 e_emp 员工信息表 1 emp_id 员工编号 e_emp 员工信息表 2 company 公司简称 e_emp 员工信息表 3 name 人员姓名 e_emp 员工信息表 4 gender 性别 e_emp 员工信息表 5 birth_date 出生日期 e_emp 员工信息表 6 ethnic 民族 e_emp 员工信息表 7 service_years 工龄 e_emp 员工信息表 8 education 学历 e_emp 员工信息表 9 qualification 职业资格 e_emp 员工信息表 10 function 岗位职能 e_emp 员工信息表 11 talent_type 骨干类型 e_emp 员工信息表 12 position 岗位类别 e_emp 员工信息表 13 major 专业类别 e_emp 员工信息表 14 status 在岗状态 e_emp_changes 员工变动信息表 1 emp_id 员工ID e_emp_changes 员工变动信息表 2 emp_code 员工编号 e_emp_changes 员工变动信息表 3 change_reason 变动原因 e_emp_changes 员工变动信息表 4 employment_type 劳动关系类别 e_emp_changes 员工变动信息表 5 year 年度 e_emp_changes 员工变动信息表 6 month 月度 e_emp_changes 员工变动信息表 7 type 类型 e_emp_changes 员工变动信息表 8 is_deleted 删除标签 e_emp_training 员工培训记 1 class_no 课程编号 e_emp_training 员工培训记 2 emp_id 员工编号 e_emp_training 员工培训记 3 course 课程名称 e_emp_training 员工培训记 4 grade 成绩 e_emp_training 员工培训记 5 created_at 考核时间 e_order 订单表 1 ORDERID 订单编号 e_order 订单表 2 ZTIME 下单时间 e_order 订单表 3 PRODUCTID 产品编号 e_order 订单表 4 SALE_AMOUNT 销售数量 e_order 订单表 5 CUSTOMID 客户编号 e_product 产品信息表 1 PRODUCTID 产品编号 e_product 产品信息表 2 PRODUCTNAME 产品名称 e_product 产品信息表 3 PRICE 【实操题】 查询 Class1班级data_visualization平均分与Class2中data_visualization平均分的差值。 结果输出:Class1_data_visualization平均分,Class2_data_visualization平均分,差值。
03-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值