国庆 day 2 下午
最大值(max)
Time Limit:1000ms Memory Limit:128MB
题目描述
LYK有一本书,上面有很多有趣的OI问题。今天LYK看到了这么一道题目:
这里有一个长度为n的正整数数列ai(下标为1~n)。并且有一个参数k。
你需要找两个正整数x,y,使得x+k<=y,并且y+k-1<=n。并且要求a[x]+a[x+1]+…+a[x+k-1]+a[y]+a[y+1]+…+a[y+k-1]最大。
LYK并不会做,于是它把题扔给了你。
输入格式(max.in)
第一行两个数n,k。
第二行n个数,表示ai。
输出格式(max.out)
两个数表示x,y。若有很多种满足要求的答案,输出x最小的值,若x最小仍然还有很多种满足要求的答案,输出y最小的值。
输入样例
5 2
6 1 1 6 2
输出样例
1 4
对于30%的数据n<=100。
对于60%的数据n<=1000
对于100%的数据1<=n<=100000,1<=k<=n/2,1<=ai<=10^9。
思路:维护连续的k个数的和 的后缀最大值
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define max(a,b) a>b?a:b #define MAXV 500010 long long ma,mx,my,ans; long long lx[MAXV],ly[MAXV],lt[MAXV],rt[MAXV]; long long a[MAXV],rtm[MAXV],sum[MAXV],summ[MAXV]; void ch(long long &x,long long y,long long z,int pos,int poss,int i){ if(y<z){ x=z; lx[i]=poss; } else{ x=y; lx[i]=pos; } } void hc(long long &x,long long y,long long z,int pos,int poss,int i){ if(y<z){ x=z; ly[i]=poss; } else{ x=y; ly[i]=pos; } } void cc(long long &x,long long y,int i){ if(x<y){ x=y; mx=lx[i-1]; my=ly[i]; } } int main(){ freopen("max.in","r",stdin); freopen("max.out","w",stdout); int t,n,i,temp,k; scanf("%d%d",&n,&k); for(i=1;i<=n;i++){ scanf("%d",&a[i]); sum[i]=sum[i-1]+a[i]; ans+=a[i]; } for(int i=1;i<=n;i++) summ[i]=ans-sum[i-1]; for(int i=1;i<=k;i++) lt[i]=sum[i],lx[i]=1; for(int i=n;i>=n-k+1;i--) rt[i]=summ[i],ly[i]=i; for(int i=k+1;i<=n;i++) ch(lt[i],lt[i-1],sum[i]-sum[i-k],lx[i-1],i-k+1,i); for(int i=n-k;i>=1;i--) hc(rt[i],rt[i+1],summ[i]-summ[i+k],ly[i+1],i,i); for(i=k+1;i<=n-k+1;i++) cc(ma,lt[i-1]+rt[i],i); cout<<mx<<" "<<my; return 0; }
吃东西(eat)
Time Limit:2000ms Memory Limit:1024MB
题目描述
一个神秘的村庄里有4家美食店。这四家店分别有A,B,C,D种不同的美食。LYK想在每一家店都吃其中一种美食。每种美食需要吃的时间可能是不一样的。
现在给定第1家店A种不同的美食所需要吃的时间a1,a2,…,aA。
给定第2家店B种不同的美食所需要吃的时间b1,b2,…,bB。
以及c和d。
LYK拥有n个时间,问它有几种吃的方案。
输入格式(eat.in)
第一行5个数分别表示n,A,B,C,D。
第二行A个数分别表示ai。
第三行B个数分别表示bi。
第四行C个数分别表示ci。
第五行D个数分别表示di。
输出格式(eat.out)
一个数表示答案。
输入样例
11 3 1 1 1
4 5 6
3
2
1
输出样例
2
对于30%的数据A,B,C,D<=50
对于另外30%的数据n<=1000。
对于100%的数据1<=n<=100000000,1<=A,B,C,D<=5000,0<=ai,bi,ci,di<=100000000。
30分的暴力:
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 5010 using namespace std; int n,A,B,C,D; long long ans,cnt1,cnt2; int num1[MAXN*MAXN],num2[MAXN*MAXN]; int a[MAXN],b[MAXN],c[MAXN],d[MAXN]; struct nond{ int x,y; bool operator < (nond b) const{ return x>b.x; } }v; priority_queue<nond>que,q,qu; int main(){ freopen("eat.in","r",stdin); freopen("eat.out","w",stdout); scanf("%d%d%d%d%d",&n,&A,&B,&C,&D); for(int i=1;i<=A;i++) scanf("%d",&a[i]); sort(a+1,a+1+A); for(int i=1;i<=B;i++){ scanf("%d",&b[i]); v.x=b[i]+a[1];v.y=1; que.push(v); } while(!que.empty()&&que.top().x<=n){ nond now=que.top(); num1[++cnt1]=now.x; que.pop(); if(now.y+1<=A){ now.x=now.x-a[now.y]+a[now.y+1]; now.y+=1; que.push(now); } } for(int i=1;i<=C;i++) scanf("%d",&c[i]); sort(c+1,c+1+C); for(int i=1;i<=D;i++){ scanf("%d",&d[i]); v.x=d[i]+c[1];v.y=1; q.push(v); } while(!q.empty()&&q.top().x<=n){ nond now=q.top(); num2[++cnt2]=now.x; q.pop(); if(now.y+1<=C){ now.x=now.x-c[now.y]+c[now.y+1]; now.y+=1; q.push(now); } } for(int i=1;i<=cnt2;i++){ v.x=num2[i]+num1[1];v.y=1; qu.push(v); } while(!qu.empty()&&qu.top().x<=n){ nond now=qu.top(); ans++; qu.pop(); if(now.y+1<=cnt1){ now.x=now.x-num1[now.y]+num1[now.y+1]; now.y+=1; qu.push(now); } } cout<<ans; }
正解思路:分组背包。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 5005 #define M 25000005 #define N 100000005 using namespace std; int A,B,C,D; long long ans; int n,cnt,cnt1,maxn; int f[N],bns[M],cns[M]; int a[MAXN],b[MAXN],c[MAXN],d[MAXN]; int main(){ freopen("eat.in","r",stdin); freopen("eat.out","w",stdout); scanf("%d%d%d%d%d",&n,&A,&B,&C,&D); for(int i=1;i<=A;i++) scanf("%d",&a[i]); for(int i=1;i<=B;i++) scanf("%d",&b[i]); maxn=0; for(int i=1;i<=A;i++) for(int j=1;j<=B;j++) if(a[i]+b[j]<=n){ f[a[i]+b[j]]++; maxn=max(maxn,a[i]+b[j]); } for(int i=0;i<=maxn;i++) while(f[i]){ f[i]--; bns[++cnt]=i; } for(int i=1;i<=C;i++) scanf("%d",&c[i]); for(int i=1;i<=D;i++) scanf("%d",&d[i]); maxn=0; for(int i=1;i<=C;i++) for(int j=1;j<=D;j++) if(c[i]+d[j]<=n){ f[c[i]+d[j]]++; maxn=max(maxn,c[i]+d[j]); } for(int i=0;i<=maxn;i++) while(f[i]){ f[i]--; cns[++cnt1]=i; } int now; for(now=cnt1;now>=1;now--) if(bns[1]+cns[now]<=n) break; for(int i=1;i<=cnt;i++){ ans+=now; while(now&&bns[i+1]+cns[now]>n) now--; } cout<<ans; }
分糖果(candy)
Time Limit:1000ms Memory Limit:128MB
题目描述
总共有n颗糖果,有3个小朋友分别叫做L,Y,K。每个小朋友想拿到至少k颗糖果,但这三个小朋友有一个共同的特点:对3反感。也就是说,如果某个小朋友拿到3颗,13颗,31颗,333颗这样数量的糖果,他就会不开心。(也即它拿到的糖果数量不包含有一位是3)
LYK掌管着这n颗糖果,它想问你有多少种合理的分配方案使得将这n颗糖果全部分给小朋友且没有小朋友不开心。
例如当n=3,k=1时只有1种分配方案,当n=4,k=1时有3种分配方案分别是112,121,211。当n=7,k=2时则不存在任何一种合法的方案。
当然这个答案可能会很大,你只需输出答案对12345647取模后的结果就可以了。
输入格式(candy.in)
第一行两个数表示n,k。
输出格式(candy.out)
一个数表示方案总数。
输入样例
99999 1
输出样例
9521331
对于30%的数据n<=100
对于50%的数据n<=1000。
对于另外30%的数据k=1。
对于100%的数据3<=n<=10^10000,1<=k<=n/3,且n,k不包含前导0。
数位DP
dp[i][j][k][l][t] 表示n的前i位,分完后的余数为j,第1/2/3个小朋友的第i位能否随便填 的方案数
再枚举3个小朋友分别分多少转移
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 10003 #define mod 12345647 using namespace std; char s[MAXN]; int a[MAXN],b[MAXN]; int dp[MAXN][3][2][2][2]; void ADD(int &i,int j){ i+=j; if(i>=mod) i-=mod; } int main(){ freopen("candy.in","r",stdin); freopen("candy.out","w",stdout); scanf("%s",s+1); int len1=strlen(s+1); for(int i=1;i<=len1;++i) a[i]=s[i]-'0'; scanf("%s",s+1); int len2=strlen(s+1); for(int i=1;i<=len2;++i) b[i+len1-len2]=s[i]-'0'; dp[0][0][0][0][0]=1; for(int i=0;i<len1;i++) for(int j=0;j<3;j++) for(int k=0;k<2;k++) for(int l=0;l<2;l++) for(int t=0;t<2;t++) if(dp[i][j][k][l][t]) for(int s1=0;s1<=9;s1++) if(s1!=3) for(int s2=0;s2<=9;s2++) if(s2!=3) for(int s3=0;s3<=9;s3++) if(s3!=3){ int I=i+1; int J=j*10+a[i+1]-s1-s2-s3; if(J<0||J>2) continue; if(!k&&s1<b[i+1]) continue; int K=(k||s1>b[i+1]); if(!l&&s2<b[i+1]) continue; int L=(l||s2>b[i+1]); if(!t&&s3<b[i+1]) continue; int T=(t||s3>b[i+1]); ADD(dp[I][J][K][L][T],dp[i][j][k][l][t]); } int ans=0; for(int k=0;k<2;k++) for(int l=0;l<2;l++) for(int t=0;t<2;t++) ADD(ans,dp[len1][0][k][l][t]); printf("%d",ans); }