首先我想说一件很憋屈的事情:
对不起,我不配打NOIP(什么是NOIP?)
40/0/0
第一题没想到优化错解的方法,少了20分。
6309. 完全背包
(File IO): input:backpack.in output:backpack.out
Time Limits:
1000 ms Memory Limits: 262144 KB Detailed Limits
完全背包裸题?
需要加一点科技来优化:
- 给定任意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 }
6308. 中间值
(File IO): input:median.in output:median.out
Time Limits:
1000 ms Memory Limits: 131072 KB Detailed Limits
Goto ProblemSet
考虑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 }
6306. Sequence
(File IO): input:sequence.in output:sequence.out
Time Limits:
1000 ms Memory Limits: 524288 KB Detailed Limits
Goto ProblemSet
考场上推了好久,没有卵用,因为太菜了……
明天数论讲完再补上吧。