T1:
题目描述:
NYG有一个神奇的背包,每放进去一个物品,背包的体积就会变大。
也就是说,每放进一个物品,背包会被占用一定的体积,但是紧接着背包的总体积又
会增大一定的值(注意是在放入物品后背包总体积才增大)。
NYG发觉这个背包十分好用,于是不由自主地想到了一个问题。
现在给出背包初始容量V以及n个物品,每一个物品两个值a; b,分别表示物品所占体积
和放入背包后背包增大的体积。
NYG想知道能否把所有物品装进去?
因为NYG比较老实,这么简单的问题自然装作不会做的样子。
于是他来请教你。
样例输入:
3
7 9269
21366 1233
7178 23155
16679 23729
15062 28427
939 6782
24224 9306
22778 13606
5 22367
17444 5442
16452 30236
14893 24220
31511 13634
4380 29422
7 18700
25935 4589
24962 9571
26897 14892
20822 2380
21103 12648
32006 22912
23367 20674
样例输出:
Yes
Yes
No
解析:
考虑贪心。对于b>=a,显然对a权值从小到大排序即可。对于b<a,按b从大到小排序。下面给出证明:
将整个过程倒着看,用了a体积相当于增加了a体积,增加了b体积相当于用了b体积。类比于b>=a的过程,我们肯定想让占背包体积小即b值小的优先。但由于是倒着看,所以正着的时候就按b从大到小排序。
时间复杂度O(nlogn)
代码:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long LL; const int MAXN=100010; int T; struct Backpack{ int a,b; }s1[MAXN],s2[MAXN]; int n; LL h; int cnt1=0,cnt2=0; inline int read(){ int ret=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-f;c=getchar();} while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} return ret*f; } bool cmp1(Backpack A,Backpack B){ return A.a<B.a; } bool cmp2(Backpack A,Backpack B){ return A.b>B.b; } int main(){ freopen("backpack.in","r",stdin); freopen("backpack.out","w",stdout); T=read(); while(T--){ cnt1=0;cnt2=0; n=read();h=1LL*read(); for(int i=1;i<=n;++i){ int a=read(),b=read(); if(b-a>=0){ s1[++cnt1].a=a;s1[cnt1].b=b; }else{ s2[++cnt2].a=a;s2[cnt2].b=b; } } sort(s1+1,s1+cnt1+1,cmp1); bool flag=false; for(int i=1;i<=cnt1;++i){ h-=1LL*s1[i].a; if(h<0){ printf("No\n"); flag=true; break; } h+=1LL*s1[i].b; } if(flag) continue; sort(s2+1,s2+cnt2+1,cmp2); for(int i=1;i<=cnt2;++i){ h-=1LL*s2[i].a; if(h<0){ printf("No\n"); flag=true; break; } h+=1LL*s2[i].b; } if(flag) continue; printf("Yes\n"); } return 0; }
T2:
题目描述:
样例输入:
30
15 15 3 30 9 30 27 11 5 15 20 10 25 20 30 15 30 15 25 5 10 20 7 7 16 2 7 7 28 7
样例输出:
1 13
9
解析:
看到题目中问满足条件的最大值,便想到二分答案。问题在于怎么check。我们发现,对于一个区间[l,r],满足条件的ak值一定是这段区间的gcd,并且是这段区间的最小值。用ST表来维护即可。
预处理复杂度O(nlogn²),check复杂度O(nlogn),总时间复杂度O(nlogn²)。
代码:
#include<cstdio> #include<iostream> using namespace std; typedef long long LL; const int MAXN=500004; LL a[MAXN]; LL Min[MAXN][25],gcd[MAXN][25]; int n; int lg[MAXN]; int ans[MAXN],top=0; inline LL read(){ LL ret=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(f=='-') f=-f;c=getchar();} while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();} return ret*f; } inline LL min(LL a,LL b){ return a<b?a:b; } inline LL Gcd(LL a,LL b){ return (!b)?a:Gcd(b,a%b); } inline void prework(){ lg[0]=-1; for(register int i=1;i<=n;++i){ lg[i]=lg[(i>>1)]+1; Min[i][0]=a[i]; gcd[i][0]=a[i]; } for(register int k=1;k<=20;++k){ for(register int i=1;i<=n-(1<<k)+1;++i){ Min[i][k]=min(Min[i][k-1],Min[i+(1<<(k-1))][k-1]); gcd[i][k]=Gcd(gcd[i][k-1],gcd[i+(1<<(k-1))][k-1]); } } } inline bool check(int len){ for(register int i=1;i<=n-len+1;++i){ if(Gcd(gcd[i][lg[len]],gcd[i+len-(1<<lg[len])][lg[len]])==min(Min[i][lg[len]],Min[i+len-(1<<lg[len])][lg[len]])) return true; } return false; } inline void calc(int len){ for(register int i=1;i<=n-len+1;++i){ if(Gcd(gcd[i][lg[len]],gcd[i+len-(1<<lg[len])][lg[len]])==min(Min[i][lg[len]],Min[i+len-(1<<lg[len])][lg[len]])) ans[++top]=i; } } inline void solve(){ int l=0,r=n; while(l<r){ int mid=(l+r+1)>>1; if(check(mid)) l=mid; else r=mid-1; } calc(l); printf("%d %d\n",top,l-1); for(register int i=1;i<=top;++i) printf("%d ",ans[i]); } int main(){ freopen("point.in","r",stdin); freopen("point.out","w",stdout); scanf("%d",&n); for(register int i=1;i<=n;++i) a[i]=read(); prework(); solve(); return 0; }
T3
题目描述:
样例输入:
4
1 1 2
10 6 6
3 1 4
100 1000 100000
样例输出:
2
512
198
540522901
解析:
首先考虑dp方程:设cnt[i]为以i为长度的区间的等比数列的个数,dp[i]为已经填了i位的拆分总数。
显然dp[i]=dp[i-1]*cnt[1]+dp[i-2]*cnt[2]+...+dp[0]*cnt[n];
这个式子显然可以用矩阵快速幂优化。那么问题就变成了怎么快速处理cnt数组。
代码:
#include<cstdio> #include<iostream> #include<cmath> using namespace std; typedef long long LL; const int mod=1e9+7; LL n; int l,r,T; LL cnt[35]; struct Matrix{ LL m[35][35]; Matrix(){ for(int i=1;i<=27;++i) for(int j=1;j<=27;++j) m[i][j]=0LL; } }dw; int gcd(int x,int y){ return (!y)?x:gcd(y,x%y); } void prework(){ for(int i=0;i<=25;++i) cnt[i]=0; cnt[1]=r-l+1; cnt[2]=1LL*(r-l+1)*(r-l)%mod; int lim=sqrt(r)+1; for(int x=1;x<=lim;++x) for(int y=1;y<x;++y) if(gcd(x,y)==1){ int xx=x,yy=y; for(int k=2;1LL*xx*x<=r;++k) xx*=x,yy*=y,cnt[k+1]+=1LL*max(0,r/xx-(l-1)/yy); } for(int i=3;i<=25;++i) cnt[i]=(cnt[i]<<1)%mod; } Matrix mul(Matrix A,Matrix B){ Matrix C; for(int i=1;i<=27;++i) for(int j=1;j<=27;++j) for(int k=1;k<=27;++k) C.m[i][j]=(C.m[i][j]+A.m[i][k]*B.m[k][j]%mod)%mod; return C; } Matrix qpow(Matrix x,LL y){ Matrix res=dw; while(y){ if(y&1) res=mul(res,x); x=mul(x,x); y>>=1; } return res; } void work(){ Matrix A; A.m[1][1]=1; Matrix B; for(int i=1;i<=25;++i) B.m[i][1]=cnt[i]; B.m[27][1]=1LL*(r-l+1); for(int i=1;i<=25;++i) B.m[i][i+1]=1LL; B.m[1][27]=1LL; B.m[27][27]=1LL; B=qpow(B,n); printf("%lld\n",mul(A,B).m[1][1]%mod); } int main(){ freopen("excellent.in","r",stdin); freopen("excellent.out","w",stdout); scanf("%d",&T); for(int i=1;i<=27;++i) dw.m[i][i]=1; while(T--){ scanf("%lld%d%d",&n,&l,&r); prework(); work(); } return 0; }