小总结:

今天早上最先做的是先把昨天的那道恶心的树剖题调出来,直到吃完饭回来我才弄完-_- 。

之后我尝试着把ftp里面的对拍程序改成c++格式的(ftp里面的check.sh老师老师的时候不让下了),在考试之前五分钟终于成功了,一开考就兴奋的打了一遍(然鹅一上午并没有用QAQ)

T1:小猫爬山

暑期集训第十一天(7-2)题解及总结

这道题老师给出的答案竟然是暴搜???n<=18不应该是状压???看到这道题想到上周做过的一道名为"宝藏"的题目,那道题目之中我们用到一个循环来把一个二进制数字进行拆分,来进行预处理,这道题我们也可以用类似的思想来进行处理,先把不同状态的重量算一下,能装下就把这个dp赋值为1,否则为无穷大,之后对不同二进制数字进行拆分,进行拼接,求出最优解即可(之后看时间效率好像刚刚水过???)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1<<20;
int w[50],trans[N],dp[N];
int lowbit(int x){
	return x & -x; 
}
int count(int x){
	int cnt=1;
	while(x){
		if(x&1) return cnt;
		x>>=1; cnt++;
	}
	return cnt;
}
int cal(int x){
	int ans=0;
	while(x){
		int now=count(x);
		ans+=w[now];
		x-=lowbit(x);
	}
	return ans;
}
signed main(){
	int n,m;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;++i) scanf("%lld",&w[i]);
	int ed=(1<<n)-1;
	memset(dp,0x3f,sizeof(dp));
	for(int i=0;i<=ed;++i){
		int now=cal(i);
		if(now<=m) dp[i]=1;
	}
	for(int i=0;i<=ed;++i){
		for(int j=i;j;j=(j-1)&i){
			int k=i^j;
			dp[i]=min(dp[i],dp[j]+dp[k]);
		}
	}
	printf("%lld\n",dp[ed]);
	return 0;
}

T2:猴腮雷

暑期集训第十一天(7-2)题解及总结

 

 

 看到这个题目还以为这道题猴赛雷(很厉害),但是其实就是一个板子题,我们曾经做过一道题目叫做"没有上司的舞会",和这道题是一摸一样的,就是一个树归的板子,就不解释什么了.

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10;
struct Node{
	int next,to;
}edge[N];
int Head[N],tot,w[N];
void Add(int x,int y){
	edge[++tot].to=y;
	edge[tot].next=Head[x];
	Head[x]=tot;
}
int dp[N][2];
void dfs(int u,int fa){
	dp[u][1]+=w[u];
	for(int i=Head[u];i;i=edge[i].next){
		int v=edge[i].to;
		if(v==fa) continue;
		dfs(v,u);
		dp[u][1]+=dp[v][0];
		dp[u][0]+=max(dp[v][1],dp[v][0]);
	}
}
signed main(){
	int n;
	scanf("%lld",&n);
	for(int i=1;i<=n;++i) scanf("%lld",&w[i]);
	int x,y;
	while(scanf("%lld%lld",&x,&y)==2&&x&&y){
		Add(x,y);Add(y,x);
	}
	dfs(1,1);
	printf("%lld\n",max(dp[1][0],dp[1][1]));
	return 0;
}

 T3:小烈送菜

暑期集训第十一天(7-2)题解及总结

看到这道题之后先想了半个小时,又想了十五分钟,默默的看了一下表,默默的看了一下数据范围,之后去打了一个30pts的暴力....

这道题的思维还是挺清奇的,我们想到小烈一个来回一定会把所有的人都送到,我们的价值和就是相邻的分数的乘积,这好像和顺序没有任何关系???于是我们可以把小烈的返回的方向反转,换为两个人从起点向终点进行行走,两个人扫过的范围必须满足所有的人都被送到,于是考虑dp[i][j]表示第一个人在i,另一个在j的情况,由于i,j可以互换,于是有f[i][j]==f[j][i],这样我们就可以始终假设i>j,我们的下一状态dp[i+1][j]可以从i和j两个地方进行转移,但是如果从j转移,另一个人此时一定在i点,于是存在转移:f[i+1][j]=max(f[i+1][j],f[i][j]+a[i]∗a[i+1]),f[i+1][i]=max(f[i+1][i],f[i][j]+a[j]∗a[i+1])

之后就解决了.

#include<bits/stdc++.h>
using namespace std;
const int N=2505;
int a[N],dp[N][N],ans=0;
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	for(int i=1;i<=n;++i)
		for(int j=0;j<i;++j){
			dp[i+1][j]=max(dp[i+1][j],dp[i][j]+a[i]*a[i+1]);
			dp[i+1][i]=max(dp[i+1][i],dp[i][j]+a[j]*a[i+1]);
		}
	for(int i=0;i<n;++i)
		ans=max(ans,dp[n][i]+a[n]*a[i]);
	printf("%d\n",ans);
	return 0;
}

 推老师博客++:https://www.cnblogs.com/hbhszxyb/p/13223698.html

T4:Siano

暑期集训第十一天(7-2)题解及总结

 

 (为什么线段树都这么难调呀QAQ)

我们不难发现草的高度无论何时都具有单调性,长得高的永远高,于是我们考虑排序后用线段数来进行维护区间长度,并用二分来进行查询左边界,但是这样的时间效率是n*log^2的,只能拿到六十分,于是考虑如何去掉二分的过程,我们可以维护一个区间的最大值,(其实就是右儿子的大小,右面永远比左边大),之后进行从右边到左的查询,直到遇到一个小于修改值的,这样我们就可以砍掉一个log,成功晋级为nlogn的时间效率,这样就不会超时啦,但是这道题的代码不怎么好调,最初只有100行,让我调完后就成了150行???其实后来发现我的方法繁琐了,其实是不用单独的修改操作的,这里放一个大佬的代码吧.

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define ll long long
 5 using namespace std;
 6 const int N=5e5+10;
 7 struct Tree{
 8     int l,r;
 9     ll sum,tar,tard,a,last,Mx,Mi;
10 }T[N<<2];
11 int a[N];
12 #define ls rt<<1
13 #define rs rt<<1|1
14 void Build(int rt,int l,int r){
15     T[rt].l=l;T[rt].r=r;T[rt].tar=-1;
16     if(l==r){
17         T[rt].a=a[l];
18         return ;
19     }
20     int mid=l+r>>1;
21     Build(ls,l,mid);
22     Build(rs,mid+1,r);
23     T[rt].a=T[ls].a+T[rs].a;
24 }
25 void pushdown(int rt){
26     if(T[rt].tar==-1)return;
27     T[ls].sum=T[rt].tar*(T[ls].r-T[ls].l+1);
28     T[rs].sum=T[rt].tar*(T[rs].r-T[rs].l+1);
29     T[ls].tar=T[rs].tar=T[ls].Mx=T[ls].Mi=T[rs].Mx=T[rs].Mi=T[rt].tar;
30     T[ls].tard=T[rs].tard=T[ls].last=T[rs].last=T[rt].tard;
31     T[rt].tar=-1;
32 }
33 ll query(int rt,ll d,ll b){
34     T[rt].sum+=T[rt].a*(d-T[rt].last);
35     T[rt].Mx+=a[T[rt].r]*(d-T[rt].last);
36     T[rt].Mi+=a[T[rt].l]*(d-T[rt].last);
37     T[rt].last=d;
38     ll ans=0;
39     if(T[rt].Mx<=b)return 0;
40     if(T[rt].Mi>b){
41         ans+=T[rt].sum-b*(T[rt].r-T[rt].l+1);
42         T[rt].tard=T[rt].last=d;
43         T[rt].tar=b;
44         T[rt].sum=b*(T[rt].r-T[rt].l+1);
45         T[rt].Mx=T[rt].Mi=b;
46         return ans;
47     }
48     pushdown(rt);
49     ans=query(ls,d,b)+query(rs,d,b);
50     T[rt].sum=T[ls].sum+T[rs].sum;
51     T[rt].Mi=T[ls].Mi;T[rt].Mx=T[rs].Mx;
52     return ans;
53 }
54 int main(){
55     int n,m;
56     scanf("%d%d",&n,&m);
57     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
58     sort(a+1,a+n+1);
59     Build(1,1,n);
60     for(int i=1;i<=m;i++){
61         ll d,b;
62         scanf("%lld%lld",&d,&b);
63         printf("%lld\n",query(1,d,b));
64     }
65 }
大佬代码

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-20
  • 2021-08-22
  • 2021-10-21
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-02-05
  • 2022-12-23
相关资源
相似解决方案