比赛链接:这里
OP
E的知识点好像需要补,赛时想到的都爆TLE
A 股神
贪心 / DP
思路
朴素的贪心思想:
次日若比此日股价高,且没有买入,则所有金币买入;
次日若比此日股价低,且有买入,则全部卖出;
注意输出时转换成金币输出;
注意浮点误差;
注意第0天也可以进行买入操作。
DP方法可以参考ph大佬的题解。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll M=1e9+7; const int INF=0x3f3f3f3f;
int main() { double gp[502],w=1,g=0; int n,i; cin>>n; for(i=1;i<=n;i++)scanf("%lf",&gp[i]); gp[0]=1; for(i=0;i<n;i++) { if(g==0) { if(gp[i+1]>gp[i]) { g=w/gp[i]; w=0; } } else { if(gp[i+1]<gp[i]) { w=g*gp[i]; g=0; } } } if(g>0)w+=g*gp[n]; printf("%.2lf",w); return 0; }
|
B 酒馆决斗
模拟
思路
排序后进行模拟,注意每次出招都有可能造成对方减员,而不是每回合;
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll M=1e9+7; const int INF=0x3f3f3f3f; struct qd {int a,b;}qua[100005],shp[100005]; bool cmp(qd x,qd y) { if(x.a==y.a)return x.b>y.b; return x.a>y.a; } int main() { int n,m,i,j; cin>>n>>m; for(i=1;i<=n;i++)scanf("%d%d",&qua[i].a,&qua[i].b); for(i=1;i<=m;i++)scanf("%d%d",&shp[i].a,&shp[i].b); sort(qua+1,qua+1+n,cmp); sort(shp+1,shp+1+m,cmp); i=j=1; for(;i<=n&&j<=m;) { shp[j].b-=qua[i].a; if(shp[j].b<=0)j++; if(j>m)break; qua[i].b-=shp[j].a; if(qua[i].b<=0)i++; } if(i<=n)printf("Quasrain");else printf("SHP"); printf(" wins, left "); printf("%d",max(m-j+1,n-i+1)); return 0; }
|
C 求 k 整除最大元素和
DP
思路
建立dp方程dp[i][j]=max(dp[i−1][(j−g%k+k)%k]+g,dp[i−1][j]),dp[i][j]代表有前 i 个数时,mod(k)=j 时的最大和;
[(j−g%k+k)%k]是为了防止计算后的余数变负或溢出;
赛时没找到简单的压缩至一维dp的方法(实际上应该有),而开[102][100005]会MLE;
因为处理 [i] 时只需要 [i] 与 [i-1] 行数数据;
所以通过开 [2][100005] ,并在 [1] 每一行处理完后,将数据更新[0]内,以节省内存;
数据最大和为1e14,可以放心大胆地用 ll 进行dp;
注意dp初始值的设定。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll M=19260817,N=1e9+9; const int INF=0x3f3f3f3f;
ll dp[2][102]={0}; int main() { int n,k,i,j,g; cin>>n>>k; for(i=1;i<k;i++)dp[0][i]=-1e14-1; for(i=1;i<=n;i++) { scanf("%d",&g); for(j=0;j<k;j++) { dp[1][j]=max(dp[0][(j-g%k+k)%k]+g,dp[0][j]); } for(j=0;j<k;j++) { dp[0][j]=dp[1][j]; } } printf("%lld",(dp[0][0])>0?dp[0][0]%M:0); return 0; }
|
D 取快递
贪心
思路
以a为排序依据,降序排列;
从用时最长的开始,直至超能力时间和大于该快递用时,或该快递的超能力用时大于标准用时时,跳出贪心;
跳出后比较标准用时与超能力用时和的最大值输出。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll M=1e9+7; const int INF=0x3f3f3f3f;
struct qd {int a,b;}qdb[100005]; bool cmp(qd x,qd y) { if(x.a==x.b)return x.b<y.b; return x.a<y.a; } int main() { int n,i,j,tb=0; cin>>n; for(i=1;i<=n;i++)scanf("%d%d",&qdb[i].a,&qdb[i].b); sort(qdb+1,qdb+1+n,cmp); for(i=n;i>=1;i--) { if(qdb[i].b>qdb[i].a)break; else { if(tb+qdb[i].b<=qdb[i].a)tb+=qdb[i].b; else break; } if(tb>=qdb[i].a)break; } printf("%d",max(tb,qdb[i].a)); return 0; }
|
原题被删除了,在这里大概描述一下:
题目描述
有一长度为n的数组,初始值全为0,现对其进行m此操作:
每次操作遵循op a b
的输入形式
若op为1,则对第a位的数加b;
若op为2,则输出数组[a,b]区间上的非零数个数;
若op为3,则输出数组[a,b]区间上数字之和;
输入共m+1行,第一行输入n,m;
接下来m行输入m次操作;
对于每一次操作2或操作3,输出一行答案;
数据范围:
1<=n<=1e9
1<=m<=1e5
op∈{1,2,3}
1<=a<=b<=1e9
大概是这个样的,目前还没什么好想法。
F 幸运数字
暴力模拟
思路
暴力模拟即可。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll M=1e9+7; const int INF=0x3f3f3f3f;
int main() { int m,i,j,ans=0; cin>>m; for(i=1;i<=m;i++) { int sum=0; j=i; while(j) { sum+=j%10; j/=10; } if(i%sum==1)ans++; } cout<<ans; return 0; }
|
G 有限小数
进制转换
思路
可以参考浮点数进制转换;
我先将获得的A进制数转换为10进制,再进行处理,方便操作与理解。
对于进制转换,我们可以不关心转换成的B进制数具体是什么,只关心是否有剩余;
所以我们就可以暴力地进行足够多位的转换,直接看结果是否有剩余即可。
关于进一步优化可以参考ph大佬的题解。
PS:ph大佬在进制转换的字符串遍历方向错了的情况下依然过掉了9/10,%%%。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll M=19260817,N=1e9+9; const int INF=0x3f3f3f3f;
ll ctoten(string& n,ll a) { ll ans=0,ma=1; for(int i=n.length()-1;i>=0;i--) { ans+=(n[i]>='0'&&n[i]<='9')?(n[i]-'0')*ma:(n[i]-'A'+10)*ma; ma*=a; } return ans; } int main() { ll a,b,nu,nd,i; string up,down; cin>>up>>down>>a>>b; nu=ctoten(up,a); nd=ctoten(down,a); if(nu>=nd)nu-=nd; for(i=1;i<=10000000;i++) { nu*=b; nu%=nd; } if(!nu)printf("Yes"); else printf("No"); return 0; }
|
H 子数组和
滑窗
思路
从右界累加至和不小于 k ,再从左界累减至不大于k;
若此时和值为k,则输出左右界;
否则即再执行上面的操作;
若遍历完都没有和为k的情况,则输出-1;
注意处理边界。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll M=1e9+7; const int INF=0x3f3f3f3f;
int main() { ll n,a[1003],k,i,j,sum; cin>>n>>k; for(i=1;i<=n;i++)scanf("%lld",&a[i]); i=1,j=0,sum=0; for(;i<=n&&j<=n;) { while(sum<k&&j<=n)j++,sum+=a[j]; while(sum>k&&i<=n)sum-=a[i],i++; if(sum==k)break; } if(j==n+1||i==n+1)printf("-1"); else printf("%lld %lld",i,j); return 0; }
|
ED
码字较急,难免有疏漏与错误,欢迎评论区讨论与反馈。