标签:continue span 开头 contains space 技术分享 rds any put
InputThe first line of the input gives the number of test cases T; T test cases follow.
Each case begins with one line with four integers N, W, pw, dw : the number of words, page width, picture width and left margin.
The next line contains N integers aiai, indicates i-th word consists of aiai characters.
The third line contains one integer Q.
Then Q lines follow, each line contains the values of xi and hi, indicates the starting line and the image height of the image.
Limits
T≤10T≤10
1≤N,W,Q≤1051≤N,W,Q≤105
1≤pw,ai≤W1≤pw,ai≤W
0≤dw≤W?pw0≤dw≤W?pwOutputFor each query, output one integer denotes the minimum number of rows.
Sample Input
2 2 7 4 3 1 3 3 1 2 2 2 5 2 3 8 2 3 1 1 3 1 1 1
Sample Output
2 3 3 1
题解:
这个题目,的确,第一眼看上去是在倍增什么呢?可以倍增字节,但是复杂度还是不对,那么还有什么量可以倍增呢?就只剩下行数了,好久没有写倍增了,什么边界处理什么的都忘了,所以讲一下实现吧。
dp[i][j]表示在没有图的情况下以第i个单词为开头,覆盖2^j次方单词包括i在内需要几个,这个初始状态就是对于每个单词,暴力匹配他还需要多少单词,付给dp[i][0],然后有一个显然的状态转移dp[i][j]=dp[i][j-1]+dp[i+dp[i][j-1]][j-1];
这里处理一下边界,如果dp[i][j-1]||dp[i+dp[i][j-1]][j-1]==0就不处理,保证之后单词数不够的情况下,dp[i][j]=0。
然后再次设一个状态dp2[i][j]表示在有图的情况下以第i个单词为开头,覆盖2^j次方单词包括i在内需要几个,初始值和状态转移都是一样的。求的时候因为不可能超过20,就从20for到0,能跳就跳就可以了。
具体就是没到图的开头时用dp1跳到图的开头,然后用dp2,跳过图中,最后如果还剩下单词就继续用dp跳,有细节,推荐看一下代码。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #define MAXN 101000 using namespace std; int dp[MAXN][22],dp2[MAXN][22]; int hi[MAXN],star[MAXN]; int a[MAXN]; int n,w,pw,dw,q; void init(){ scanf("%d%d%d%d",&n,&w,&pw,&dw); memset(a,0,sizeof(a)); for(int i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&q); memset(star,0,sizeof(star)); memset(hi,0,sizeof(hi)); for(int i=1;i<=q;i++) scanf("%d%d",&star[i],&hi[i]); } void pre(){ memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++){ int sum=a[i],j=i+1; while(sum+a[j]+1<=w&&j<=n) sum+=a[j++]+1; dp[i][0]=j-i; } for(int j=1;j<=20;j++) for(int i=1;i<=n;i++){ if(!dp[i][j-1]||!dp[i+dp[i][j-1]][j-1]) continue; dp[i][j]=dp[i][j-1]+dp[i+dp[i][j-1]][j-1]; } memset(dp2,0,sizeof(dp2)); for(int i=1;i<=n;i++){ int j=i,flag=0,sum=0; while(sum+a[j]+flag<=dw&&j<=n) sum+=a[j++]+flag,flag=1; int k=j; sum=0,flag=0; while(sum+a[k]+flag<=w-pw-dw&&k<=n) sum+=a[k++]+flag,flag=1; dp2[i][0]=k-i; } for(int j=1;j<=20;j++) for(int i=1;i<=n;i++){ if(!dp2[i][j-1]||!dp2[i+dp2[i][j-1]][j-1]) continue; dp2[i][j]=dp2[i][j-1]+dp2[i+dp2[i][j-1]][j-1]; } } int jump1(int now){ int ans=0; for(int j=20;j>=0;j--){ if(!dp[now][j]) continue; if(now+dp[now][j]-1<=n){ now+=dp[now][j]; ans+=1<<j; } } return ans; } int jump2(int now,int cen){ for(int j=20;j>=0;j--){ if(!dp[now][j]) continue; if((1<<j)<=cen){ cen-=(1<<j); now+=dp[now][j]; } } return now; } int jump3(int now,int cen){ for(int j=20;j>=0;j--){ if(!dp2[now][j]) continue; if((1<<j)<=cen){ cen-=(1<<j); now+=dp2[now][j]; } } return now; } void work(){ for(int i=1;i<=q;i++){ int x=star[i],h=hi[i],tmp=jump1(1); if(tmp<=x-1){ printf("%d\n",tmp+h); continue; } int ans=x+h-1,now=jump2(1,x-1); now=jump3(now,h); if(now<=n) ans+=jump1(now); printf("%d\n",ans); } } int main() { int t;cin>>t; while(t--){ init(); pre(); work(); } return 0; }
标签:continue span 开头 contains space 技术分享 rds any put
原文地址:http://www.cnblogs.com/renjianshige/p/7571684.html