不及普及组的测试

解题报告

期望

T1 期望得分 100 实际得分 100

T2期望得分 100 实际得分40

T3期望得分 50 实际得分 0

T1 backpack

多重背包板子题
\(n\leq 1000\) 很显然,是不需要任何优化的,同时最下面写了一个二进制优化

/*
 by : Zmonarch
 知识点 : 
  1000不需要用二进制和单调队列优化 
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <vector>
#define int long long
#define inf 2147483647 
#define qwq register 
const int kmaxn = 2e3 + 20 ; 
const int kmod = 998244353 ; 
namespace Base
{
	inline int Min(int a , int b) {return a < b ? a : b ;}
	inline int Max(int a , int b) {return a < b ? b : a ;}
	inline int gcd(int a , int b) {return !b ? a : gcd(b , a % b) ;}
	inline int Abs(int a ) {return a < 0 ? - a : a ;} 
}
inline int read()
{
	int  x = 0 , f = 1 ; char ch = getchar()  ;
	while(!isdigit(ch)) {if(ch == '-') f = - 1 ; ch = getchar() ; }
	while( isdigit(ch)) {x = x * 10 + ch - '0' ; ch = getchar() ; }
	return x * f ; 
}
int n , m ; 
int v[kmaxn] , w[kmaxn] , c[kmaxn] , f[kmaxn][kmaxn] ;  
signed main()
{
	freopen("backpack.in" , "r" , stdin) ; 
	freopen("backpack.out" , "w" , stdout) ; 
	n = read() , m = read() ; 
	for(qwq int i = 1 ; i <= n ; i++) 
	v[i] = read() , w[i] = read() , c[i] = read() ; 
	for(qwq int i = 1 ; i <= n ; i++) 
	{
		for(qwq int j = 0 ; j <= m ; j++) 
		{
			for(qwq int k = 0 ; k <= c[i] ; k++) 
			{
				if(k * v[i] <= j) 
				{
					f[i][j] = Base::Max(f[i - 1][j - k * v[i]] + k * w[i] , f[i][j] ); 
				}
			}
		}
	}
	printf("%I64d\n" , f[n][m]) ; 
	return 0 ; 
} 
/*
	int total=1;
	for(qwq int i=1;i<=n;i++)
	{
		for(qwq int j=1;j<=c[i];j<<=1)
		{
			a[total]=j*w[i];
			b[total++]=j*v[i];
			c[i]-=j;
		}
		
		if(c[i])
		{
			a[total]=c[i]*w[i];
			b[total++]=c[i]*v[i];
		}
		
	}
	
	for(qwq int i=1;i<=total;i++)//转化成01背包 
	{
		for(qwq int j=m;j>=b[i];j--)
		{
			f[j]=max(f[j],f[j-b[i]]+a[i]);
		}
	}
*//*
 by : Zmonarch
 知识点 : 
  1000不需要用二进制和单调队列优化 
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <vector>
#define int long long
#define inf 2147483647 
#define qwq register 
const int kmaxn = 2e3 + 20 ; 
const int kmod = 998244353 ; 
namespace Base
{
	inline int Min(int a , int b) {return a < b ? a : b ;}
	inline int Max(int a , int b) {return a < b ? b : a ;}
	inline int gcd(int a , int b) {return !b ? a : gcd(b , a % b) ;}
	inline int Abs(int a ) {return a < 0 ? - a : a ;} 
}
inline int read()
{
	int  x = 0 , f = 1 ; char ch = getchar()  ;
	while(!isdigit(ch)) {if(ch == '-') f = - 1 ; ch = getchar() ; }
	while( isdigit(ch)) {x = x * 10 + ch - '0' ; ch = getchar() ; }
	return x * f ; 
}
int n , m ; 
int v[kmaxn] , w[kmaxn] , c[kmaxn] , f[kmaxn][kmaxn] ;  
signed main()
{
	freopen("backpack.in" , "r" , stdin) ; 
	freopen("backpack.out" , "w" , stdout) ; 
	n = read() , m = read() ; 
	for(qwq int i = 1 ; i <= n ; i++) 
	v[i] = read() , w[i] = read() , c[i] = read() ; 
	for(qwq int i = 1 ; i <= n ; i++) 
	{
		for(qwq int j = 0 ; j <= m ; j++) 
		{
			for(qwq int k = 0 ; k <= c[i] ; k++) 
			{
				if(k * v[i] <= j) 
				{
					f[i][j] = Base::Max(f[i - 1][j - k * v[i]] + k * w[i] , f[i][j] ); 
				}
			}
		}
	}
	printf("%I64d\n" , f[n][m]) ; 
	return 0 ; 
} 
/*
	int total=1;
	for(qwq int i=1;i<=n;i++)
	{
		for(qwq int j=1;j<=c[i];j<<=1)
		{
			a[total]=j*w[i];
			b[total++]=j*v[i];
			c[i]-=j;
		}
		
		if(c[i])
		{
			a[total]=c[i]*w[i];
			b[total++]=c[i]*v[i];
		}
		
	}
	
	for(qwq int i=1;i<=total;i++)//转化成01背包 
	{
		for(qwq int j=m;j>=b[i];j--)
		{
			f[j]=max(f[j],f[j-b[i]]+a[i]);
		}
	}
*/

T2 circulate

给定 \(x,y,l,r\) 四个数字,并形成一个序列 \(x , x+1,x+2…y-1 , y\) 的一个序列 ,输出 \(l\to r\) 的区间和。

\(x-y \leq 10^6 , l ,r \leq 10 ^9\)

solution

首先看到区间和 , 首先我就想到了线段树 ,然后我们发现 \(s\) 的长度很小,那么我们就对 \(s\) 建立线段树,然后我们对区间进行划分,我们找出 \(l\)\(s\) 上的投影,然后求区间 \(l\to s.len\) 的和,预计复杂度 \(O(\frac{(l+r)}{len_s} + \log l + \log r + len_s \times \log len)\)
应该炸不了,结果 \(T\) 了,然后我们直接转化一成循环节来搞一下,然后类比分块来搞一下。就 \(OK\)

/*
 by : Zmonarch
 知识点 :

*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <vector>
#define int long long
#define inf 2147483647
const int kmaxn = 1e6 + 10 ;
const int kmod = 998244353 ;
namespace Base
{
	inline int Min(int a , int b) {return a < b ? a : b ;}
	inline int Max(int a , int b) {return a < b ? b : a ;}
	inline int gcd(int a , int b) {return !b ? a : gcd(b , a % b) ;}
	inline int Abs(int a ) {return a < 0 ? - a : a ;}
}
inline int read()
{
	int  x = 0 , f = 1 ; char ch = getchar()  ;
	while(!isdigit(ch)) {if(ch == '-') f = - 1 ; ch = getchar() ; }
	while( isdigit(ch)) {x = x * 10 + ch - '0' ; ch = getchar() ; }
	return x * f ;
}
int x , y , L , R , cnt , ss ;  
int num[kmaxn] , cover[kmaxn] , sum[kmaxn]; 
signed main()
{
	x = read() , y = read() , L = read() , R = read() ; 
	if(x < y) std::swap(x , y) ;
	for(int i = x ; i <= y ; i++) 
	{
		int k = i , s = 0 ; 
		while(k) 
		{
			cover[++s] = k % 10 ;
			k /= 10 ; 
		}
		for(int j = s ; j >= 1 ; j--) 
		num[++cnt] = cover[j] ;
	}
	for(int i = 1 ; i <= cnt ; i++) sum[i] = sum[i - 1] + num[i] ; 
	int lenr = R / cnt , lenl = L / cnt ;  
	int r = R % cnt ; if(r == 0) r = cnt ;
	int l = L % cnt ; if(l == 0) l = cnt ;
	printf("%lld\n" , (lenr - lenl - 1 ) * sum[cnt] + sum[cnt] - sum[l - 1] + sum[r] ) ; 
	return 0 ;
}

T3 merge

【description】

\(Cindy\)\(Dan\) 在玩一个游戏。
一开始 \(Cindy\) 想出了 \(N\) 个数,接着她把这 \(N\) 个数全部给了 \(Dan\)
\(Dan\) 得到这组数后,它会挑出 \(3\) 个数(如果不足 \(3\) 个则全部挑出)。\(Dan\) 会把这几个数加起来变成一个数,然后再把这个数与剩下的数再放到一起。\(Dan\) 会一直这样做,直到最后只剩下一个数。
\(Cindy\) 则会在旁边记下每次 \(Dan\) 得到的数,她把这些数加起来,作为本次游戏的得分。她想知道,对于一组数,\(Dan\) 能得到的最大的得分是多少?

数据 \(n\leq 10^6\)

【solution】:

有一个结论,就是最大得分就是最大数不断去运算。没有什么证明,既然得分最大,我们令最大的数进行运算的次数最多,然后就OK了,我当时看错题目了。

/*
 by : Zmonarch
 知识点 :
 对于 50% 的数据,是可以搜索做的 
*/
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <vector>
#define int long long
#define inf 2147483647
const int kmaxn = 1e3 + 10 ;
const int kmod = 998244353 ;
namespace Base
{
	inline int Min(int a , int b) {return a < b ? a : b ;}
	inline int Max(int a , int b) {return a < b ? b : a ;}
	inline int gcd(int a , int b) {return !b ? a : gcd(b , a % b) ;}
	inline int Abs(int a ) {return a < 0 ? - a : a ;}
}
inline int read()
{
	int  x = 0 , f = 1 ; char ch = getchar()  ;
	while(!isdigit(ch)) {if(ch == '-') f = - 1 ; ch = getchar() ; }
	while( isdigit(ch)) {x = x * 10 + ch - '0' ; ch = getchar() ; }
	return x * f ;
}
int n , num[kmaxn] , ret ; 
std::priority_queue<int> q ; 
signed main()
{
	n = read() ;
	for(int i = 1 ; i <= n ; i++) q.push(read());
	int ret = 0 , num = 0; 
	if(n <= 3) 
	{
		while(!q.empty()) 
		{
			ret += q.top() ; 
			q.pop() ; 
		}
		printf("%lld\n" , ret) ; 
		return 0; 
	}
	while(q.size() != 1)
	{
		int tmp = 0 , sum = 0 ; 
		while(!q.empty())
		{
			sum += q.top() ;
			q.pop() ; 
			tmp++ ; 
			if(tmp == 3) break ; 
		}
		ret += sum ; 
		q.push(sum) ; 
	}
	printf("%lld\n" , ret) ; 
	return 0 ;
}

经验:

  • \(1.\) 首先先拿出 \(30\) 分钟读题,读错题非常亏
  • \(2.\) 先不要质疑自己推出来的结论。
posted @ 2021-03-10 14:03  SkyFairy  阅读(67)  评论(2编辑  收藏  举报