将 2022 拆分成 10 个互不相同的正整数之和, 总共有多少种拆分方法?
注意交换顺序视为同一种方法, 例如 2022=1000+1022 和 1022+1000 就视为同一种方法。
这是一道结果填空的题, 你只需要算出结果后提交即可。本题的结果为一 个整数, 在提交答案时只填写这个整数, 填写多余的内容将无法得分。
dp动态规划,a[i][j][v]代表1到i个数中,选j个数,和为v的答案总数;每次到i时有两种状况,选i和不选i
选i: a[i][j][v] a[i-1][j-1][v-i] 相对上次来说,j要加一,i要加一,但是此次选i因此要求上 一次 是v-i;
不选i: a[i][j][v] a[i-1][j][v];
因此a[i][j][v] =a[i-1][j-1][v-i]+a[i-1][j][v];但是要考虑有时候i放不进去的情况,比如v=2,但i=5,i不能放因此递推公式有了
if(v - i >= 0 && j - 1 >= 0){ //v要大于等于i,并且至少要选一个数;
f[i][j][v] = f[i - 1][j - 1][v - i];
}
f[i][j][v] += f[i - 1][j][v]; //每次必定加上
#include
using namespace std;
long long f[2030][11][2030];
int main(){
f[0][0][0]=1;
for(int i=1;i<=2022;i++){
for(int j=0;j<=10;j++){
for(int v=0;v<=2022;v++){
if(v - i >= 0 && j - 1 >= 0){
f[i][j][v] = f[i - 1][j - 1][v - i];
}
f[i][j][v] += f[i - 1][j][v];
}
}
}
cout<
B:钟表
在 12 小时制的钟表中, 有分针、时针、秒针来表示时间。记分针和时 针之间的夹角度数为 A(0≤A≤180) 、分针和秒针之间的夹角度数为 (0≤B≤180)。而恰好在 s 时 f 分 m 秒时, 满足条件 A=2B 且 0≤f<60;0≤m<60, 请问 s,f,m 分别是多少。
请你找出一个 0 时 0 分 0 秒以外的解。
注意时针、分针、秒针都围绕中心匀速转动。
提交格式为三个由一个空格隔开的整数, 分别表示 s,f,m 。如 3 11 58 表示 3 点 11 分 58 秒。
这是一道结果填空的题, 你只需要算出结果后提交即可。本题的结果为三个由一个空格隔开的整数, 在提交答案时只填写为三个由一个空格隔开的整数, 填写多余的内容将无法得分。
角度?我们把角度看为比例,比如30秒就是30/60=0.5,然后模拟就行了
#include
#include
using namespace std;
int main(){
for(int h=0;h<=6;h++){
for(int fen=0;fen<60;fen++){
for(int miao=0;miao<60;miao++) {
double miaoj=miao/60.00000;
double fenj=fen/60.00000+(miao/60.00000)/60.000000;
double hj= h/12.000000+(fen+miao/60.00000)/(12*60.00000);
double a=fabs(fenj-hj);
if(a>0.5) a=1-a;
double b=fabs(fenj-miaoj);
if(b>0.5) b=1-b;
if(fabs(a-2*b)<=1e-8 && h!=0){
cout<
C:卡牌
这天, 小明在整理他的卡牌。
他一共有 n 种卡牌, 第 i 种卡牌上印有正整数数 i(i∈[1,n]), 且第 i 种卡牌 现有 ai 张。
而如果有 n 张卡牌, 其中每种卡牌各一张, 那么这 n 张卡牌可以被称为一 套牌。小明为了凑出尽可能多套牌, 拿出了 m 张空白牌, 他可以在上面写上数 ii, 将其当做第 i 种牌来凑出套牌。然而小明觉得手写的牌不太美观, 决定第 ii 种牌最多手写 bi 张。
请问小明最多能凑出多少套牌?
输入共 3 行, 第一行为两个正整数 n,m 。
第二行为 nn 个正整数 a1,a2,…,an 。
第三行为 nn 个正整数 b1,b2,…,bn 。
一行, 一个整数表示答案。
4 5
1 2 3 4
5 5 5 5
3
这 5 张空白牌中, 拿 2 张写 1 , 拿 1 张写 2 , 这样每种牌的牌数就变为了3,3,3,4, 可以凑出 3 套牌, 剩下 2 张空白牌不能再帮助小明凑出一套。
对于 30% 的数据, 保证 0n≤2000;
对于 100% 的数据, 保证 ai,bi≤2n;m≤n2 。
暴力解法:
#include
using namespace std;
int n,m;
long long a[200005];
long long b[200005];
long long ans;
int main(){
long long min=1e16;
cin>>n>>m;
for(int i=0;i>a[i];
if(min>a[i]){
min=a[i];
}
}
for(int i=0;i>b[i];
}
ans=min;
for(int i=0;i0&&m>0) {
m--;
b[i]--;
a[i]++;
}else{
cout<
二分法:
#include
#include
using namespace std;
long long n,m,l,r;
long long a[200005];
long long b[200005];
long long kk;
bool check(long long x){
long long s = 0;
for (int i = 0; i < n; i++) { //判断x套牌可以凑出来不
if (x - a[i] <= b[i]) {
s += max(x - a[i],kk );
}
else return false;
}
if (s <= m) return true;
return false;
}
int main(){
cin>>n>>m;
for(int i=0;i>a[i];
l = min(l, a[i]);
}
for(int i=0;i>b[i];
r=max(r,a[i]+b[i]); //以可以达到的最大数目为右指针
}
int ans;
while(l<=r){
long long mid=(l+r)/2; //二分查找可以凑成几套牌
if(check(mid)){
ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
cout<
给定一个正整数 N 。你可以对 N 的任意一位数字执行任意次以下 2 种操 作:
将该位数字加 1 。如果该位数字已经是 9 , 加 1 之后变成 0 。
将该位数字减 1 。如果该位数字已经是 0 , 减 1 之后变成 9 。
你现在总共可以执行 1 号操作不超过 A 次, 2 号操作不超过 B 次。 请问你最大可以将 NN 变成多少?
第一行包含 3 个整数: N,A,B 。
一个整数代表答案。
123 1 2
933
对百位数字执行 2 次 2 号操作, 对十位数字执行 1 次 1 号操作。
对于 30% 的数据, 0≤A,B≤10
对于 100% 的数据, 0≤A,B≤100
#include
#include
using namespace std;
string n;
long long ans;
int a,b;
void dfs(int x,long long an){ //a代表每次遍历的数
int t=n[x]-'0'; //位数转为int
if(n[x]){ //防止为空
int c=min(a,9-t);
a-=c;
dfs(x+1,an*10+t+c);
a+=c;
if(b>t){
b=b-t-1;
dfs(x+1,an*10+9);
b=b+t+1;
}
}else{
ans=max(ans,an);
}
}
int main(){
cin>>n>>a>>b;
dfs(0,0); //0号字符
cout<
E:出差
A 国有 N 个城市, 编号为 1…N 。小明是编号为 1 的城市中一家公司的员 工, 今天突然接到了上级通知需要去编号为 N 的城市出差。
由于疫情原因, 很多直达的交通方式暂时关闭, 小明无法乘坐飞机直接从 城市 1 到达城市 N, 需要通过其他城市进行陆路交通中转。小明通过交通信息 网, 查询到了 M 条城市之间仍然还开通的路线信息以及每一条路线需要花费的 时间。
同样由于疫情原因, 小明到达一个城市后需要隔离观察一段时间才能离开 该城市前往其他城市。通过网络, 小明也查询到了各个城市的隔离信息。(由于 小明之前在城市 1 , 因此可以直接离开城市 1 , 不需要隔离)
由于上级要求, 小明希望能够尽快赶到城市 N, 因此他求助于你, 希望你 能帮他规划一条路线, 能够在最短时间内到达城市 N 。
第 1 行: 两个正整数N,M,N 表示 A 国的城市数量, M 表示末关闭的路 线数量
第 2 行: N 个正整数, 第 i 个整数 Ci 表示到达编号为i 的城市后需要隔离 的时间
第 3 …M+2 行: 每行 3 个正整数,u,v,c, 表示有一条城市 uu 到城市 v的 双向路线仍然开通着, 通过该路线的时间为 c
第 1 行: 1 个正整数, 表示小明从城市 1 出发到达城市 N 的最短时间(到 达城市 N, 不需要计算城市 N 的隔离时间)
4 4
5 7 3 4
1 2 4
1 3 5
2 4 3
3 4 5
13
对于 100% 的数据, 1≤N≤1000,1≤M≤10000,1≤Ci≤200,1≤u,v≤ N,,1≤c≤1000
最短路径采用Dijkstra算法会快一点;
#include
#include
#include
using namespace std;
int n,m; //n个城市,m条路线
int geli[10005]; //到每个城市的隔离时间
int luxian[10005][10005];
int juli[10005]; //到一点的最短距离
bool vis[10005];
int dj(){
memset(juli,0x3f3f3f3f,sizeof(juli));
juli[1]=0; //距离起点为0
geli[1]=0; //出自己城市不隔离
geli[n]=0; //到达终点不需要隔离
for(int i=1;i<=n;i++){ //剔除n个
int s=-1;
for(int j=1;j<=n;j++){
if(!vis[j]&&((s==-1)||(juli[j]>n>>m;
for(int i=1;i<=n;i++){
cin>>geli[i];
}
memset(luxian,0x3f3f3f3f,sizeof(luxian)); //无穷大
for(int i=1;i<=n;i++){
luxian[i][i]=0; //自己到自己为0
}
for(int i=0;i>a>>b>>c;
luxian[a][b]=luxian[b][a]=min(c,luxian[a][b]);
}
int ans=dj();
cout<
F:费用报销
小明在出差结束后返回了公司所在的城市, 在填写差旅报销申请时, 粗心 的小明发现自己弄丢了出差过程中的票据。
为了弥补小明的损失, 公司同意小明用别的票据进行报销, 但是公司财务 要求小明提交的票据中任意两张的日期差不小于 K 天, 且总金额不得超过实际 差旅费用 M 。
比如财务要求 K=7 时, 若小明提交了一张 1 月 8 日的票据, 小明就不能 提交 1 月 2 日至 1 月 14 日之间的其他票据, 1 月 1 日及之前和 1 月 15 日及之 后的票据则可以提交。
公司的同事们一起给小明凑了 N 张票据, 小明现在想要请你帮他整理一 下, 从中选取出符合财务要求的票据, 并使总金额尽可能接近 M 。
需要注意, 由于这些票据都是同一年的, 因此 12 月底的票据不会影响到 1 月初票据的提交。这一年不是闰年。
第 1 行: 3 个整数, N,M,K
第 2…N+1 行: 每行 3 个整数 mi,di,vi, 第 i+1 行表示第 i 张票据时间 的月份 mi 和日期 di,vi 表示该票据的面值
第 1 行: 1 个整数, 表示小明能够凑出的最大报销金额
4 16 3
1 1 1
1 3 2
1 4 4
1 6 8
10
选择 1 月 3 日和 1 月 6 日的票据
对于 100% 的评测用例, 1≤N≤1000,1≤M≤5000,1≤K≤50,1≤mi≤ 12,,1≤di≤31,1≤vi≤400
日期保证合法。
动态规划问题, 先将n张票据以结构体保存下来,然后转化为数组,但是一天可能有好几张票据,因此我们要将一天票据进行比较。然后利用递推公式:
选i票据:ans[i] ans[i-k]+面值[i] 前提小于等于m'
不选i票据:ans[i] ans[i-1]
因此:ans[i]=max(ans[i-k]+面值[i],ans[i-1])
然后就是在于一天中每个票据挨个比较
#include
#include
#include
using namespace std;
int n,m,k; //n代表n个票据,m钱,k天
int piao1[400];
int ans[500];
vector piao2[400];
int month12[12]={31,28,31,30,31,30,31,31,30,31,30,31};
struct piao{
int month;
int day;
int qian;
};
piao a[1005];
int getday(int x,int y){
int ans=y;
for(int i=0;i>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>a[i].month>>a[i].day>>a[i].qian;
} //输入结构体
int daymax=0;
for(int i=1;i<=n;i++){
int day=getday(a[i].month,a[i].day);
if(piao1[day]){
piao2[day].push_back(a[i].qian);
}else{
piao1[day]=a[i].qian;
}
daymax=max(day,daymax); //全转为天数,重合的装在vector里
}
for(int i=1;i<=daymax;i++){ //遍历每天的票据
if(piao1[i]==0) {
ans[i]=ans[i-1]; //这一天没有票,等于上一天的值
}else{
if(piao2[i].size()==0){ //这一天只有一张票
if(ans[i-1]<=m){
ans[i]=ans[i-1];
}
if(ans[i-k]+piao1[i]<=m){
ans[i]=max(ans[i],ans[i-k]+piao1[i]);
}
}else{
if(ans[i-1]<=m){
ans[i]=ans[i-1]; //这一天有多张票
}
if(ans[i-k]+piao1[i]<=m){
ans[i]=max(ans[i],ans[i-k]+piao1[i]);
}
int len=piao2[i].size();
for(int j=0;j
G:故障
在软件或系统开发中, 我们会遇到各种各样的故障。为了从故障现象反推 故障原因, 工程师们会总结一种叫做相关性矩阵的二维表格, 来表示故障原因 与故障现象之间的关系。比如:
其中每行表示一种故障原因, 每一列表示一种故障现象。该矩阵表示故障 原因 AA 可能产生故障现象 2、3、4, 故障原因 BB 可能产生故障现象 1、3。
在实际开发过程中, 如果出现了故障原因, 工程师就可以根据故障现象, 去计算每种故障原因产生的概率, 并按照概率大小对故障原因进行排查, 以达 到快速定位故障原因的目的。
现在, 我们假设系统开发中同一时间只会出现一种故障原因, 并且故障原 因引起各故障现象是独立事件。举个例子来说:
假设系统现在发生了故障原因 A, 有 1/3的概率出现故障现象 2 , 有 1/4 的概 率出现故障现象 3 , 有 1/2的概率出现故障现象 4。由于 3 种现象是独立发生的, 因此有 1/3*1/4*1/2 的概率同时出现故障 2、3、4。
约定若相关性矩阵中没有 ' x ' 记号, 则表示该故障原因一定不会产生某故 障现象, 比如故障原因 A, 一定不会产生故障现象 1。
根据历史经验数据, 我们统计得到了每一种故障原因出现的概率以及每一 种故障原因对应的故障现象产生概率。
现在已知系统出现的故障现象, 求问各个故障原因发生的概率。
第 1 行: 2 个正整数 N,M,N 表示故障原因的个数(编号 1…N ), M 表 示故障现象的个数 (编号 1 1…M)
第 2 行: N 个整数, 第 i 个数表示故障原因 i 产生的概率 Pi.
第 3…N+2 行: 每行 M 个整数, 第 i+2 行第 j 个整数 Pij 表示故障原 因 i 出现故障现象 j 的概率 (百分比).
第 N+3 行: 1 个正整数 K, 表示目前出现的故障现象数量
第 N+4 行: K 个正整数, 依次为当前出现的故障现象编号, 不会重复
第 1…N 行: 按概率从高到低输出每种故障原因及其可能的概率, 若出现 概率相同则优先输出编号小的故障原因。第 1 个数为故障原因编号, 第 2 个数 为故障概率 (百分比), 保留 2 位小数。
3 5
30 20 50
0 50 33 25 0
30 0 35 0 0
0 0 0 25 60
1
3
2 56.89
1 43.11
3 0.00
对于所有测试用例, 1≤N≤40,1≤M≤20,0≤Pi≤100,Σ(Pi)=100, 0≤Pij≤100,
这个题敢不敢再写得长一点,看题目半小时过去了,概率题;
就是这个算法,概率论的题,还好我们开过这门课,呜呜呜呜呜。
#include
#include
#include
#include
using namespace std;
int n,m; //n行,m列
int yuanyin[450];
int p1[450][450];
int k;
int guzhang[4500];
int vis2[450];
int vis1[450];
double dange[450];
int id[450];
bool cmp(int a,int b){
if(fabs(dange[a]-dange[b])>1e-8){
return dange[a]>dange[b]; //当不相等时返回大的,否则返回id值小的
}else{
return a>n>>m;
for(int i=1;i<=n;i++){
cin>>yuanyin[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>p1[i][j];
}
}
cin>>k;
for(int i=1;i<=k;i++){
cin>>guzhang[i];
vis1[guzhang[i]]=1; //标记故障
}
double num=0;
for(int i=1;i<=n;i++){
dange[i]=1; //便于乘
for(int j=1;j<=m;j++){
if(vis1[j]){ //此点是故障点
dange[i]=(double)dange[i]*p1[i][j]/100.0;
}else{
dange[i]=(double)dange[i]*(100-p1[i][j])/100.0;
}
}
dange[i]=(double)dange[i]*yuanyin[i]/100.0;
num+=dange[i];
}
if(fabs(num)<1e-9){
for(int i = 1 ; i <= n ; i ++){
printf("%lld 0.00\n" , i) ;
}
return 0 ;
}
for(int i=1;i<=n;i++){ //很巧妙的排序,对id排序,然后输出
id[i]=i;
dange[i]=dange[i]*100.0/num;
}
sort(id+1,id+1+n,cmp); //根据dange的值排id
for(int i=1;i<=n;i++){
printf("%lld %0.2lf\n",id[i],dange[id[i]]);
}
return 0;
}
H:机房
这天, 小明在机房学习。
他发现机房里一共有 n 台电脑, 编号为 1 到 n, 电脑和电脑之间有网线连 接, 一共有 n−1 根网线将 n 台电脑连接起来使得任意两台电脑都直接或者间 接地相连。
小明发现每台电脑转发、发送或者接受信息需要的时间取决于这台电脑和 多少台电脑直接相连, 而信息在网线中的传播时间可以忽略。比如如果某台电脑 用网线直接连接了另外 d 台电脑, 那么任何经过这台电脑的信息都会延迟 d 单 位时间 (发送方和接收方也会产生这样的延迟, 当然如果发送方和接收方都是 同一台电脑就只会产生一次延迟)。
小明一共产生了 m 个疑问: 如果电脑 ui 向电脑 vi 发送信息, 那么信息从 ui 传到 vi 的最短时间是多少?
输入共 n+m 行, 第一行为两个正整数 n,m 。
后面 n−1 行, 每行两个正整数 x,y 表示编号为 x 和 y 的两台电脑用网线 直接相连。
后面 mm 行, 每行两个正整数 ui,vi 表示小明的第i 个疑问。
输出共 m 行, 第 i 行一个正整数表示小明第 ii 个疑问的答案。
4 3
1 2
1 3
2 4
2 3
3 4
3 3
5
6
1
这四台电脑各自的延迟分别为 2,2,1,1 。
对于第一个询问, 从 2 到 3 需要经过 2,1,3, 所以时间和为 2+2+1=5 。
对于第二个询问, 从 3 到 4 需要经过 3,1,2,4, 所以时间和为 1+2+2+1=6。
对于第三个询问, 从 3 到 3 只会产生一次延迟, 所以时间为 1 。
对于 30% 的数据, 保证n,m≤1000;
对于 100% 的数据, 保证n,m≤100000 。
小编这题只会偏偏分,AC需要LCA加DFS加树的前缀和。我们看看大佬的代码吧,大体就是建一个数,统计每个节点到根节点的延时,然后通过LCA寻找询问两个点的最近公共祖先,算出最小延时。
#include
using namespace std;
typedef long long LL;
typedef pair PII;
const int N=100010;
unordered_map> gra;
int n,m;
//单个点的出度
int d[N];
//记录点i到根节点的延迟
int w[N];
//并查集数组
int q[N];
//记录答案
int res[N];
int st[N];
//存下查询
vector query[N];
//并查集查询
int find(int x){
if(x!=q[x]) q[x]=find(q[x]);
return q[x];
}
void dfs(int u,int fa)
{
w[u]+=d[u];
for(auto g:gra[u]){
if(g==fa) continue;
w[g]+=w[u];
dfs(g,u);
}
}
void tarjan(int u)
{
st[u]=1;
for(auto j:gra[u]){
if(!st[j])
{
tarjan(j);
q[j]=u;
}
}
for(auto item: query[u]){
int y=item.first,id=item.second;
if(st[y]==2){
int anc=find(y);
res[id]=w[y]+w[u]-w[anc]*2+d[anc];
}
}
st[u]=2;
}
int main()
{
cin>>n>>m;
for(int i=0;i
I:齿轮
这天, 小明在组装齿轮。
他一共有 n 个齿轮, 第 i 个齿轮的半径为 ri, 他需要把这 n 个齿轮按一定 顺序从左到右组装起来, 这样最左边的齿轮转起来之后, 可以传递到最右边的 齿轮, 并且这些齿轮能够起到提升或者降低转速 (角速度) 的作用。
小明看着这些齿轮, 突然有 QQ 个疑问:能否按一定顺序组装这些齿轮使得 最右边的齿轮的转速是最左边的齿轮的 qi 倍?
输入共 Q+2 行, 第一行为两个正整数 n,Q, 表示齿轮数量和询问数量。 第二行为 n 个正整数 r1,r2,…,rn, 表示每个齿轮的半径。
后面 Q 行, 每行一个正整数 qi 表示询问。
Q 行, 对于每个询问, 如果存在至少一种组装方案满足条件, 输出 'YES', 否则输出 'NO '。
5 3
4 2 3 3 1
2
4
6
YES
YES
NO
询问 1 方案之一 : 23341
询问 2 方案之一:42331
询问 3 没有方案
对于 15% 的数据, 保证 n,Q≤100;
对于 30% 的数据, 保证 n,Q≤2000;
对于100% 的数据, 保证 n,Q≤2×105;ri,qi≤2×105 。
语言 | 最大运行时间 | 最大运行内存 |
---|---|---|
C++ | 1s | 256M |
C | 1s | 256M |
Java | 3s | 256M |
Python3 | 5s | 256M |
暴力做法:
#include
#include
using namespace std;
int n,q;
int banjing[200005];
int xunwen[200005];
bool st[200005];
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>banjing[i];
}
for(int i=1;i<=q;i++){
cin>>xunwen[i];
}
sort(banjing,banjing+n+1);
int len=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(banjing[j]%banjing[i]==0){
int b=banjing[j]/banjing[i];
st[b]=1;
len++;
}
}
}
for(int i=1;i<=q;i++){
if(n==1&&xunwen[i]==1){
cout<<"YES"<
寻找因式:
#include
#include
#include
using namespace std;
unordered_set s;
int n,q;
int banjing[200005];
bool st[200005];
int main(){
ios_base::sync_with_stdio(false); //提高cin和cout效率
cin.tie(0);
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>banjing[i];
}
sort(banjing,banjing+n+1);
for(int i=1;i<=n;i++){
int v=banjing[i];
for(int j=1;j*j<=v;j++){
if(v%j==0){
if(s.find(j)!=s.end()){
st[v/j]=1;
}
if(s.find(v/j)!=s.end()){
st[j]=1;
}
}
}
s.insert(banjing[i]);
}
for(int i=1;i<=q;i++){
int xunwen;
cin>>xunwen;
if(n==1&&xunwen==1){
cout<<"YES"<<'\n';
}else if(st[xunwen]){
cout<<"YES"<<'\n';
}else{
cout<<"NO"<<'\n';
}
}
return 0;
}
J:搬砖
这天,小明在搬砖。
他一共有 n 块砖, 他发现第 i 砖的重量为 wi, 价值为 vi 。他突然想从这些 砖中选一些出来从下到上堆成一座塔, 并且对于塔中的每一块砖来说, 它上面 所有砖的重量和不能超过它自身的价值。
他想知道这样堆成的塔的总价值(即塔中所有砖块的价值和)最大是多少。
输入共 n+1 行, 第一行为一个正整数 nn, 表示砖块的数量。
后面 n 行, 每行两个正整数 wi,vi 分别表示每块砖的重量和价值。
一行, 一个整数表示答案。
5
4 4
1 1
5 2
5 5
4 3
10
选择第 1、2、4 块砖, 从上到下按照2、1、4 的顺序堆成一座塔, 总价值 为 4+1+5=10
对于 20% 的数据, 保证 n≤10;
对于 100% 的数据, 保证n≤1000;wi≤20;vi≤20000 。
排序后,背包动态规划
#include
#include
using namespace std;
int n;
int w;
int ans;
struct zhuan{
int jiazhi;
int zhongliang;
bool operator<(const zhuan&rhd)const {
return jiazhi+zhongliang>n;
for(int i=1;i<=n;i++){
cin>>zhuant[i].zhongliang>>zhuant[i].jiazhi;
w+=zhuant[i].zhongliang;
}
sort(zhuant+1,zhuant+n+1);
for(int i=1;i<=n;i++){
for(int j=0;j<=w;j++){
f[i][j]=f[i-1][j]; //不选
if(j>=zhuant[i].zhongliang && j-zhuant[i].zhongliang<=zhuant[i].jiazhi)
{
f[i][j]=max(f[i][j],f[i-1][j-zhuant[i].zhongliang]+zhuant[i].jiazhi);
}
ans=max(ans,f[i][j]);
}
}
cout<