【纪中受难记】——Day18:NOIPlus?

首先我想说一件很憋屈的事情:

对不起,我不配打NOIP(什么是NOIP?)

40/0/0

第一题没想到优化错解的方法,少了20分。


Description

 

Input

Output

 

Sample Input

Sample 1:
2 15
3 2
5 3

Sample 2:
3 70
71 100
69 1
1 2
 

Sample Output

Sample 1:
10

Sample 2:
140
 
 

Data Constraint

完全背包裸题?

需要加一点科技来优化:

  • 给定任意n个整数,它们之中存在若干个整数的和为n的倍数。

证明:

  对于,令:

  ,则在 n+1个数中,至少有两个数模n同余,它们的差为0,因此两个数的那一段区间和是n的倍数。

  • 设第s种物品为性价比最高的物品之中体积最小的物品。设最优情况下有x件非第s种物品,则存在一种最优情况使得

证明:

  若x>=as,那么由上一条证明可知,总有一种组合是s的倍数,拿物品s去替换不会更差。

  因此我们拿s填满背包,剩下100*as的空间做完全背包即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll N=1e6+10;
 5 ll n,C,dp[N];
 6 ll v[N],w[N];
 7 long double maxl;
 8 ll maxv=1e9;
 9 ll maxw;
10 inline ll read(){
11     ll x=0,f=1;
12     char c=getchar();
13     while(!isdigit(c)){
14         if(c=='-') f=-1;
15         c=getchar();
16     }
17     while(isdigit(c)){
18         x=x*10+c-'0';
19         c=getchar();
20     }
21     x*=f;
22     return x;
23 }
24 int main(){
25     freopen("backpack.in","r",stdin);
26     freopen("backpack.out","w",stdout);
27     n=read(),C=read();
28 
29     for(int i=1;i<=n;i++){
30         v[i]=read(),w[i]=read();
31         if((long double)w[i]/v[i]>=maxl){
32             if((long double)w[i]/v[i]==maxl&&v[i]>maxv){
33                 continue;
34             }
35             maxl=(long double)w[i]/v[i];
36             maxv=v[i];
37             maxw=w[i];
38         }
39     }
40     ll ans=0;
41     if((C/maxv)-100>0){
42         ans+=((C/maxv)-100)*maxw;
43         C-=((C/maxv)-100)*maxv;
44     }
45     for(register int i=1;i<=n;i++){
46         for(register int j=v[i];j<=C;j++){
47             dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
48         }
49     }
50     printf("%lld",dp[C]+ans);
51     return 0;
52 }

Description

 

Input

Output

 

Sample Input

5 5
12 41 46 68 69
35 61 82 84 96
2 1 4 3 5
1 0 5 75
2 2 4 3 4
2 3 4 1 5
2 1 4 2 4
 

Sample Output

68
68
68
61
 

Data Constraint

考虑O(1)修改,O(log区间长)查询。

我们将k拆成两半,分别在两个区间(a[l,r],b[l,r])中找第k大,如果数组a位置的数小于b位置的数,那么a左端的数无法做出贡献,因此缩小区间范围到a[mid+1,r],反之同理。

最后处理一下细节即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const ll N=1e6+10;
 5 ll n,m;
 6 ll a[N],b[N],k,xx,yy,zz,l1,l2,r1,r2;
 7 inline ll read(){
 8     register ll x=0,f=1;
 9     char c=getchar();
10     while(!isdigit(c)){
11         if(c=='-') f=-1;
12         c=getchar();
13     }
14     while(isdigit(c)){
15         x=x*10+c-'0';
16         c=getchar();
17     }
18     x*=f;
19     return x;
20 }
21 ll query(ll l,ll r,ll x,ll y,ll k){
22     if(l>r)return b[x+k-1];
23     if(x>y)return a[l+k-1];
24     if(k==1) return min(a[l],b[x]);
25     ll m1=min(l+k/2-1,r),m2=min(x+k/2-1,y);
26     if(a[m1]<b[m2]) return query(m1+1,r,x,y,k-(m1-l+1));
27     else return query(l,r,m2+1,y,k-(m2-x+1));
28 }
29 int main(){
30     freopen("median.in","r",stdin);
31     freopen("median.out","w",stdout);
32     n=read(),m=read();
33     for(register ll i=1;i<=n;i++) a[i]=read();
34     for(register ll i=1;i<=n;i++) b[i]=read();
35     for(register ll i=1;i<=m;i++){
36         k=read();
37         if(k==1){
38             xx=read(),yy=read(),zz=read();
39             if(xx){
40                 b[yy]=zz;
41             }
42             else a[yy]=zz;
43         }
44         else{
45             l1=read(),r1=read(),l2=read(),r2=read();
46             printf("%lld\n",query(l1,r1,l2,r2,(r1-l1+1+r2-l2+1+1)>>1));
47         }
48     }
49     return 0;
50 }

Description

 

Input

Output

 

Sample Input

2 5 4
 

Sample Output

29
 

Data Constraint

考场上推了好久,没有卵用,因为太菜了……

明天数论讲完再补上吧。

猜你喜欢

转载自www.cnblogs.com/Nelson992770019/p/11374101.html