国庆清北刷题冲刺班 Day2 下午
来源:互联网 发布:python drdos 编辑:程序博客网 时间:2024/05/04 11:19
最大值(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]最大。
K<=n/2
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。.
//考场爆零代码 ==> 本场比赛直接GG 120 分 草草收场#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib>using namespace std;inline void read(int &x){ x=0; int f=1; char c=getchar(); while(c>'9'||c<'0'){ if(c=='-')f=-1; c=getchar(); } while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;}#define MAXN 100005int n,k,a[MAXN];long long sum[MAXN];int main(int argc,char *argv[]){ freopen("max.in","r",stdin); freopen("max.out","w",stdout); read(n),read(k); int Ansi,Ansj; long long Max=0; for(int i=1;i<=n;++i) read(a[i]),sum[i]=sum[i-1]+a[i]; if(k==n/2){ printf("1 %d",n-k+1); exit(0); } for(register int i=1;i<=n;++i) for(register int j=i+k;j+k-1<=n;++j) if(sum[i+k-1]-sum[i-1]+sum[j+k-1]-sum[j-1]>Max){ Max=sum[i+k-1]-sum[i-1]+sum[j+k-1]-sum[j-1]; Ansi=i,Ansj=j; } printf("%d %d\n",Ansi,Ansj); fclose(stdin);fclose(stdout); return 0;}
分析:一个O(n^3)的做法,直接枚举两个区间,再枚举求区间和.因为用到了区间和,所以可以用前缀和优化到O(n^2).然后可以发现这个区间长度是固定的,我们可以在挪动右端点的时候右边每加一个数,左边弹一个数,用O(n)的时间处理出每一段长度为k的区间的和,在处理的过程中可以顺便记录j-k之前的区间最大值,一边求和一边统计答案就可以了。
#include<iostream>#include<cstring>#include<cstdio>using namespace std;typedef long long LL;int n,k,lastt=1,x,y;LL a[100010],r[100010],Sum,Ans,Max;int main(int argc,char *argv[]){ freopen("max.in","r",stdin); freopen("max.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1; i<=n; ++i) scanf("%lld",&a[i]); for(int i=1; i<=n; ++i){ Sum += a[i]; if(i - k > 0) Sum -= a[i - k]; r[i] = Sum; if(i - k > 0) if(Max < r[i - k]) Max = max(Max,r[i - k]),lastt=i - k; if (Max + r[i] > Ans) { Ans = max(Ans,Max + r[i]); x = max(1,lastt - k + 1); y = max(1,i - k + 1); } } printf("%d %d\n",x,y); fclose(stdin);fclose(stdout); 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。
算法剖析:Meet in The Middle
#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>using namespace std;typedef long long LL;#define MAXN 5050int a[MAXN],c[MAXN],d[MAXN],b[MAXN];int f[100000005],c1[25000010],c2[25000010],cnt1,cnt2;LL Ans=0;inline void read(int &x){ x=0; int f=1; char c=getchar(); while(c>'9'||c<'0'){ if(c=='-')f=-1; c=getchar(); } while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;}int main(int argc,char *argv[]){ freopen("eat.in","r",stdin); freopen("eat.out","w",stdout); int n,A,B,C,D,maxn = 0,cur; read(n),read(A),read(B),read(C),read(D); for(int i=1; i<=A; ++i) read(a[i]); for(int i=1; i<=B; ++i) read(b[i]); for(int i=1; i<=C; ++i) read(c[i]); for(int i=1; i<=D; ++i) read(d[i]); 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],c1[++cnt1]=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],c2[++cnt2]=i; for(cur = cnt2; cur>=1; --cur) if(c1[1] + c2[cur] <= n) break; LL Ans = 0; for(int i=1; i<=cnt1; ++i){ Ans += cur; while(cur && c2[cur] + c1[i+1] > n) --cur; } printf("%I64d\n",Ans); fclose(stdin);fclose(stdout); return 0;}
分糖果(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。
前面50分暴力,两层数据直接不是一个等级。。。
分析:这道题也不是一道特别简单的数位dp,因为要3个数的和等于n,所以我们可以在每一数位的时候枚举3个数上的这一位的值,它们的和与n的第i位相差是≤2的,因为进位最多进两位。同时还有≥k这个限制,所以我们可以设状态f[i][j][kk][l][p]表示前i位,第i+1位要向第i位进j位,kk,l,p表示枚举的3个数是否>k.每次递推的时候就能知道下一个状态,就能够就行转移了。
要求方案数,数字位数又这么多,能想到的算法只有数位dp了,从数字看向数位,是一种很好的思想的转变,如果数位dp有数字大小的限制,那么通用的办法就是加一维表示是否超出限制即可。(腿老师【张浩威】出题就是有水平啊)
//数位DP#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int mod = 12345647;char n[10010], k[10010];int a[10010],b[10010],f[10010][3][2][2][2];int main() { freopen("candy.in","r",stdin); freopen("candy.out","w",stdout); scanf("%s", n + 1); int len1 = strlen(n + 1); scanf("%s", k + 1); int len2 = strlen(k + 1); int Ans = 0; for (int i = 1; i <= len1; i++) a[i] = n[i] - '0'; for (int i = 1; i <= len2; i++) b[i + len1 - len2] = k[i] - '0'; f[0][0][0][0][0] = 1; for (int i = 0; i < len1; i++) for (int j = 0; j <= 2; j++) for (int k = 0; k <= 1; k++) for (int l = 0; l <= 1; l++) for (int p = 0; p <= 1; p++) if (f[i][j][k][l][p]) for (int q = 0; q <= 9; q++) if (q != 3) for (int q2 = 0; q2 <= 9; q2++) if (q2 != 3) for (int q3 = 0; q3 <= 9; q3++) if (q3 != 3) { int ni = i + 1, nj = j * 10 + a[i + 1] - q - q2 - q3; int nk, nl, np; if (nj < 0 || nj > 2) continue; if (k == 0 && q < b[ni]) continue; nk = (k || q > b[ni]); if (l == 0 && q2 < b[ni]) continue; nl = (l || q2 > b[ni]); if (p == 0 && q3 < b[ni]) continue; np = (p || q3 > b[ni]); f[ni][nj][nk][nl][np] += f[i][j][k][l][p]; if (f[ni][nj][nk][nl][np] >= mod) f[ni][nj][nk][nl][np] -= mod; } for (int i = 0; i <= 1; i++) for (int j = 0; j <= 1; j++) for (int k = 0; k <= 1; k++) { Ans += f[len1][0][i][j][k]; if (Ans >= mod) Ans -= mod; } printf("%d\n", Ans); fclose(stdin);fclose(stdout); return 0;}
- 国庆清北刷题冲刺班 Day2 下午
- 国庆清北刷题冲刺班 Day1 下午
- 国庆清北刷题冲刺班 Day3 下午
- 国庆清北刷题冲刺班 Day5 下午
- 国庆清北刷题冲刺班 Day6 下午
- 国庆清北刷题冲刺班 Day7 下午
- 国庆清北刷题冲刺班 Day2 上午
- 济南刷题冲刺 Day2 下午
- 国庆清北刷题冲刺班 Day1 上午
- 国庆清北刷题冲刺班 Day3 上午
- 国庆清北刷题冲刺班 Day4 上午
- 国庆清北刷题冲刺班 Day5 上午
- 国庆清北刷题冲刺班 Day6 上午
- 国庆清北刷题冲刺班 Day7 上午
- 2017国庆郑州集训Day2
- qbxt国庆水题记day2
- 济南刷题冲刺 Day1 下午
- 济南刷题冲刺 Day3 下午
- 从零开始学SpringBoot笔记001(认识)
- CentOS7 开启网卡自动获取IP
- 公开课可下载资源汇总
- javafx加载不同包中的fxml文件
- 选项卡的制作和数组
- 国庆清北刷题冲刺班 Day2 下午
- K叉树的运算
- hdu5952 Counting Cliques(爆搜)
- redis在spring中的使用
- 微信小程序设置cookie
- java中的异常是什么?
- Tyvj 1072 LCIS
- No.9 数据工程师该如何入门?
- 2016 四川省赛 H AroundtheWorld(BEST定理)