服了,跟
DP
\text{DP}
DP 杠上了,C 和 E 都在想
DP
\text{DP}
DP
C 和 D 又交了两发罚时
每题难度:
A:11
B:28
C:226
D:694
E:1504
F:2026
G:2608
A. Takahashi san 2
题意
给你一个字符串,判断这个字符串是否以 san
结尾,是输出 Yes
,否则输出 No
思路
使用 string
中的 .substr()
函数,若 s.substr(s.length()-3,3)=="san"
输出 Yes
,否则输出 No
注:s.substr(i,len)
,表示从字符串
s
s
s 的第
i
i
i 为开始的
l
e
n
len
len 个字符组成的字符串(子串)
C++ 代码
#include<bits/stdc++.h>
using namespace std;
string s;
int main(){
cin>>s;
if(s.substr(s.length()-3)=="san"){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
return 0;
}
B. Unvarnished Report
题意
输出两个字符串 S S S 和 T T T 第一个不同的位置
思路
将两个字符串用特殊符号补全,使它们长度相等即可判断
C++ 代码
#include<bits/stdc++.h>
#define sz(v) (int)v.size()
using namespace std;
string s,t;
int main(){
cin>>s>>t;
while(sz(s)<sz(t)){
s+="?";
}
while(sz(t)<sz(s)){
t+="!";
}
s=" "+s,t=" "+t;
for(int i=1;i<=sz(s);i++){
if(s[i]!=t[i]){
cout<<i<<endl;
return 0;
}
}
cout<<0<<endl;
return 0;
}
C. Separated Lunch
题意
共 n n n 个数,将它们分成两组,设这两组的和分别为 a a a 和 b b b,求 max ( a , b ) \max(a,b) max(a,b) 的最小值
思路
一开始以为是动态规划,结果直接 CE \color{#DFDF00}{\text{CE}} CE
暴力枚举每一个选分到第一组还是第二组,用二进制数表示,最多 2 20 2^{20} 220 次循环,时间足够
错误 C++ 代码 :
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=105;
const int maxm=1e8+5
int v[maxn];
int sum;
bool dp[maxn][maxm];
signed main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>v[i];
sum+=v[i];
}
dp[0][0]=1;
for(int i=0;i<n;i++){
for(int j=0;j<=sum;j++){
dp[i+1][j+v[i]]=dp[i+1][j+v[i]]||dp[i][j];
dp[i+1][j]=dp[i+1][j]||dp[i][j];
}
}
int ans=sum;
for(int i=0;i<=sum;i++){
if(dp[n][i]){
ans=min(ans,max(i,sum-i));
}
}
cout<<ans<<endl;
return 0;
}
正确 C++ 代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=25;
int n;
int k[maxn];
signed main(){
cin>>n;
for(int i=0;i<n;i++){
cin>>k[i];
}
int mn=inf;
for(int i=1;i<(1<<n);i++){
int mask=i;
int cnt=0;
int a=0,b=0;
while(cnt<n){
if(mask&1) a+=k[cnt];
else b+=k[cnt];
mask>>=1;
cnt++;
}
mn=min(mn,max(a,b));
}
cout<<mn<<endl;
return 0;
}
D. Laser Marking
题意
一个机器,要画出平面上的 n n n 条线段,每条线段从 ( A i , B i ) (A_i,B_i) (Ai,Bi) 到 ( C i , D i ) (C_i,D_i) (Ci,Di)
画线时每秒移动 T T T 个单位,不画线时每秒移动 S S S 个单位
一开始机器在位置 ( 0 , 0 ) (0,0) (0,0),你可以从 ( A i , B i ) (A_i,B_i) (Ai,Bi) 到 ( C i , D i ) (C_i,D_i) (Ci,Di) 画一条线段,也可以从 ( C i , D i ) (C_i,D_i) (Ci,Di) 到 ( A i , B i ) (A_i,B_i) (Ai,Bi) 画一条线段,一条线段不能中断
忽略抬笔和落笔的时间,问至少需要多少秒才能画完所有线段,误差需要在 1 0 − 6 10^{-6} 10−6 以内
思路
因为
N
≤
6
N \le 6
N≤6,所以使用 next_permutation()
函数来枚举画线顺序,
在每个排列中,要使用二进制数枚举画线起点和终点
结果取最小值即可
注:两点间距离公式为 dist ( ( A i , B i ) , ( C i , D i ) ) = ( C i − A i ) 2 + ( D i − B i ) 2 \text{dist}((A_i,B_i),(C_i,D_i)) = \sqrt{(C_i-A_i)^2+(D_i-B_i)^2} dist((Ai,Bi),(Ci,Di))=(Ci−Ai)2+(Di−Bi)2
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long double ld;
int n;
int s,t;
int a[10],b[10],c[10],d[10];
int pmt[10];
ld res=3e18;
int sqr(int a){
return a*a;
}
signed main(){
cin>>n>>s>>t;
for(int i=1;i<=n;i++){
pmt[i]=i;
cin>>a[i]>>b[i]>>c[i]>>d[i];
}
do{
for(int i=0;i<(1<<n);i++){
ld ans=0;
int x=0,y=0;
for(int j=1;j<=n;j++){
int cur=pmt[j];
if(i&(1<<(j-1))){
ans+=sqrt(sqr(c[cur]-x)+sqr(d[cur]-y))/s;
x=a[cur],y=b[cur];
}else{
ans+=sqrt(sqr(a[cur]-x)+sqr(b[cur]-y))/s;
x=c[cur],y=d[cur];
}
ans+=sqrt(sqr(a[cur]-c[cur])+sqr(b[cur]-d[cur]))/t;
}
res=min(ans,res);
}
}while(next_permutation(pmt+1,pmt+1+n));
cout<<fixed<<setprecision(20)<<res<<endl;
return 0;
}
E. Sensor Optimization Dilemma 2
AT又在E放二分答案!!!
题意
制造某个产品有 N N N 个步骤,第 i i i 个步骤有两个机器可以完成:
- 机器 1 1 1:每台 P i P_i Pi 元,每天可以生产 A i A_i Ai 个产品
- 机器 2 2 2:每台 Q i Q_i Qi 元,每天可以生产 B i B_i Bi 个产品
你共有 x x x 元钱来购买机器,不一定要全用完。
求出这个值的 最大值 : min i = 1 N { 第 i 天生产的产品数 } \min_{i=1}^N \{第\ i\ 天生产的产品数\} mini=1N{第 i 天生产的产品数}
思路
二分答案:
二分查找这个 min \min min 值,所以每个步骤就至少得每天生产这么多个产品,求出总钱数判断是否 ≤ x \le x ≤x
C++ 代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=105;
int n,x;
int a[maxn],b[maxn],p[maxn],q[maxn];
bool check(int cur){
int sum=0;
for(int i=0;i<n;i++){
int cost=3e18;
for(int j=0;j<100;j++){
int rest=max(cur-j*b[i],0ll); //若用j台机器2,还需生产多少个产品
int k=(rest+a[i]-1)/a[i]; //还需要多少台机器1
cost=min(cost,j*q[i]+k*p[i]); //取第i个步骤的金额最小值
}
sum+=cost; //计算总价钱
if(sum>x){
return false;
}
}
return true;
}
signed main(){
cin>>n>>x;
for(int i=0;i<n;i++){
cin>>a[i]>>p[i]>>b[i]>>q[i];
if(p[i]*b[i]>q[i]*a[i]){
swap(a[i],b[i]);
swap(p[i],q[i]);
}
}
int l=0,r=2e9;
while(l<r){
int mid=(l+r)/2;
if(check(mid)){
l=mid+1;
}else{
r=mid;
}
}
cout<<l-1<<endl;
return 0;
}