文章目录
知识点
1.二分思想
int dic(int l,int r,int x){ //l为左边界,r为右边界,x为需要查找的数
while(l<r){
mid=(l+r)/2;
if(x<=a[mid]) r=mid;
if(x>a[mid]) l=mid+1;
}
return l;
}
2.熟练运用STL容器
//定义方式
vector</*变量类型*/> /*容器名*/;
stack</*变量类型*/> /*容器名*/;
queue</*变量类型*/> /*容器名*/;
set</*变量类型*/> /*容器名*/;
map</*变量类型*/,/*变量类型*/> /*容器名*/;
//迭代器定义
/*容器类型*/</*变量类型*/(,/*变量类型*/)>::iterator /*迭代器名*/;
//插入方式
vector.push_back(x);
stack.push(x);
queue.push(x);
set.insert(x);
map[x]=y;
3.熟练运用结构体及其排序
//结构体定义
struct Node{
/*变量类型*/ /*变量名*/;
}/*结构体名*/;
//排序
bool cmp(Node x,Node y){
return /*表达式*/;
}
int main(){
sort(/*结构体数组名+起始下标*/,/*结构体数组名+终止下标*/,cmp);
}
4.高精度
string add(string s,string ss){ //高精度加法
int a[5005],b[5005],c[5005],j;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
bool f;
string sss;
a[0]=s.length();
b[0]=ss.length();
for(int i=1;i<=a[0]; i++) a[i]=s[a[0]-i]-'0';
for(int i=1;i<=b[0]; i++) b[i]=ss[b[0]-i]-'0';
for(j=1;j<=max(a[0],b[0])+1;j++){
c[j]=a[j]+b[j];
if(c[j]>=10) {
c[j]%=10;
a[j+1]++;
}
}
c[0]=j;
if(c[j+1]>0) c[0]++;
for(int i=c[0]; i>=1; i--){
if(!f&&c[i]==0) continue;
f=1;
sss+=char(c[i]+int('0'));
}
if(!f) sss+='0';
return sss;
}
string sub(string a,string b){ //高精度减法
string s;
int na[5005], nb[5005], ans[5005];
memset(na,0,sizeof(na));
memset(nb,0,sizeof(nb));
memset(ans,0,sizeof(ans));
bool pd=0;
if((a<b&&a.length()==b.length())||a.length()<b.length()){
swap(a,b);
pd=1;
}
for(int i=a.length();i>0;i--) na[i]=a[a.length()-i]-'0';
for(int i=b.length();i>0;i--) nb[i]=b[b.length()-i]-'0';
int maxl=max(a.length(),b.length());
for(int i=1;i<=maxl;i++){
if(na[i]<nb[i]){
na[i+1]--;
na[i]+=10;
}
ans[i]=na[i]-nb[i];
}
while(ans[maxl]==0) maxl--;
if(pd) s=s+'-';
for(int i=maxl;i>0;i--) s=s+char(ans[i]+int('0'));
if(maxl<1) s=s+'0';
int i=0;
while(s[i]==0&&s.length()-i>=2) i++;
string ss;
for(int j=i;j<s.length();j++) ss+=s[j];
return ss;
}
string mul(string A,string B){ //高精度乘法
string s;
int a[5005],b[5005],c[10005];
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
int lena=A.length(),lenb=B.length();
for(int i=lena-1;i>=0;i--) a[lena-i]=A[i]-'0';
for(int i=lenb-1;i>=0;i--) b[lenb-i]=B[i]-'0';
for(int i=1;i<=lena;i++)
for(int j=1;j<=lenb;j++)
c[i+j-1]+=a[i]*b[j];
int len=lena+lenb;
for(int i=1;i<=len;i++){
c[i+1]+=c[i]/10;
c[i]=c[i]%10;
}
for(;!c[len];) len--;
for(int i=max(1,len);i>=1;i--) s+=char(c[i]+int('0'));
int i=0;
while(s[i]==0&&s.length()-i>=2) i++;
string ss;
for(int j=i;j<s.length();j++) ss+=s[j];
return ss;
}
bool com(string a,string b){ //高精度比较
if(a.length()<b.length()) return 1;
if(a.length()>b.length()) return 0;
return a<b;
}
string div(string a,string b){ //高精除高精,需要高精度减法,高精度比较,高精度乘法
string xa;
bool f=0;
if(a=="0"||bj(a,b)){cout<<0;return 0;}
int lena=a.length();
for(int i=0;i<lena;i++){
if(xa=="0") xa=a[i];
else xa+=a[i];
if(com(xa,b)&&f) cout<<0;
if(com(xa,b)) continue;
f=1;
for(int j=2;j<=10;j++){
string ss;
ss=ss+char(j+int('0'));
if(com(xa,mul(b,ss))){
cout<<j-1;
string sss;
sss=sss+char(j-1+int('0'));
xa=sub(xa,mul(b,sss));
break;
}
}
}
}
测试
A. 字符替换
题目描述
把一个字符串中特定的字符全部用给定的字符替换,得到一个新的字符串。
输入格式
只有一行,由一个字符串和两个字符组成,中间用单个空格隔开。字符串是待替换的字符串,字符串长度小于等于30个字符,且不含空格等空白符;
接下来一个字符为需要被替换的特定字符;
接下来一个字符为用于替换的给定字符。
输出格式
一行,即替换后的字符串。
样例输入
hello-how-are-you o O
样例输出
hellO-hOw-are-yOu
很简单一道水题,轻松AC,核心代码如下:
for(int i=0;i<s.length();i++){
if(s[i]==a) printf("%c",b);
else printf("%c",s[i]);
}
B. 球涂色
题目描述
N个气球排成一排,从左到右依次编号为 1,2,3 … N。
每次给定2个整数a和b, L便会骑上他的“小飞鸽”牌电动车从气球a 开始到气球b 依次给每个气球涂一次颜色。但 是N次以后L已经忘记了第i个气球已经被涂过几次颜 色了,你能帮他算出每个气球被涂过几次颜色吗?
输入格式
N个气球排成一排,从左到右依次编号为 1,2,3 … N。
每次给定2个整数a和b, L便会骑上他的“小飞鸽”牌电动车从气球a 开始到气球b 依次给每个气球涂一次颜色。但 是N次以后L已经忘记了第i个气球已经被涂过几次颜 色了,你能帮他算出每个气球被涂过几次颜色吗?
输出格式
每个测试实例输出一行,包括N个整数,第i个数代表第i个气球总共被涂色的次数。
样例输入
3
1 1
2 2
3 3
3
1 1
1 2
1 3
0
样例输出
1 1 1
3 2 1
数据范围与提示
N不大于100万
一到差分的题,同样轻松AC,核心代码如下:
for(int i=1;i<=n;i++){
scanf("%lld%lld",&a,&b);
z[a]++;
z[b+1]--;
}
for(int i=1;i<=n;i++){
z[i]+=z[i-1];
printf("%lld ",z[i]);
}
C. 集合
题目描述
编写一个程序,按递增次序生成集合m的最小n个数,m的定义如下:
(1)数1属于m
(2)如果x属于m,则2x+1和3x+1也属于m
(3)此外没有别的数属于m。
输入格式
输入:一个整数n(n<=10000)
输出格式
输出:n个数,每个数占一行,由小到大输出
样例输入
10
样例输出
1
3
4
7
9
10
13
15
19
21
很简单的题,但因没判断等于的情况值得了10分,这是WA的核心代码:
for(int i=2;i<=n;i++){
if(m[l]*2+1<m[r]*3+1){
m[i]=m[l]*2+1;
l++;
}
else{
m[i]=m[r]*3+1;
r++;
}
printf("%lld\n",m[i]);
}
这是AC的:
for(int i=2;i<=n;i++){
if(m[l]*2+1<m[r]*3+1){
m[i]=m[l]*2+1;
l++;
}
else if(m[l]*2+1==m[r]*3+1){
m[i]=m[l]*2+1;
l++,r++;
}
else{
m[i]=m[r]*3+1;
r++;
}
printf("%lld\n",m[i]);
}
D. Cantor表
题目描述
现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:
我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…
输入格式
整数N(1≤N≤10000000)
输出格式
表中的第N项
样例输入
7
样例输出
1/4
找到规律就很好做了,核心代码如下:
for(int i=2;i<=n;i++){
if(!f&&p[i-1].first==1){
p[i]={p[i-1].first,p[i-1].second+1};
f=1;
continue;
}
else if(!f) p[i]={p[i-1].first-1,p[i-1].second+1};
else if(f&&p[i-1].second==1){
p[i]={p[i-1].first+1,p[i-1].second};
f=0;
continue;
}
else p[i]={p[i-1].first+1,p[i-1].second-1};
}
E.分发糖果
题目描述
老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
- 每个孩子至少分配到 1 个糖果。
- 评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢?
输入格式
输入有两行
第一行一个整数n
第二行n个整数,表示n个孩子的得分
输出格式
输出只有1个数字,表示老师至少需要准备多少颗糖果。
样例输入
3
1 0 2
样例输出
5
数据范围与提示
1≤n≤10000
0≤学生的得分≤1000
WA原因:一遍就扫过去了,没考虑后面的也会增加
WA核心代码:
for(int i=1;i<=n;i++){
while(z[i]>z[i-1]&&k[i]<=k[i-1]) k[i]++;
while(z[i]>z[i+1]&&k[i]<=k[i+1]) k[i]++;
ans+=k[i];
}
AC核心代码:
for(int i=1;i<=n;i++){
scanf("%lld",&z[i]);
k[i]=1ll;
}
for(int i=2;i<=n;i++)
if(z[i]>z[i-1])
k[i]=max(k[i],k[i-1]+1);
for(int i=n-1;i>=1;i--)
if(z[i]>z[i+1])
k[i]=max(k[i],k[i+1]+1);
for(int i=1;i<=n;i++) ans+=k[i];
F. Best Cow Fences
题目描述
给定一个长度为n的非负整数序列A,求一个平均数最大的,长度不小于L的子段。
输入格式
第一行用空格分隔的两个整数n和L;
第二行为n个用空格隔开的非负整数,Ai表示 。
输出格式
输出一个整数,表示答案的1000倍。不用四舍五入,直接输出。
样例输入
10 6
6 4 2 10 3 8 5 9 4 1
样例输出
6500
数据范围与提示
1≤n≤100000
0≤Ai≤2000
WA原因:没有考虑完全,贪心错误,WA核心代码:
for(int i=1;i<=n;i++){
scanf("%lld",&z[i]);
if(i<=l) sum+=z[i];
else sum=sum-z[i-l]+z[i];
if(i>=l) ans=max(ans,sum/l);
}
考完试后发现了贪心的错误,又TLE了,TLE核心代码:
for(int i=l;i<=n;i++){
sum=0.0;
for(int j=1;j<=n;j++){
if(j<=i) sum+=z[j];
else sum=sum-z[j-i]+z[j];
if(j>=i) ans=max(ans,sum/i);
}
}
最后用二分过了,AC核心代码:
bool check(double m){
double min_left=1e10,anss=-1e10;
for(int i=1;i<=n;i++) b[i]=a[i]-m;
for(int i=1;i<=n;i++) p[i]=p[i-1]+b[i];
for(int r=L;r<=n;r++){
min_left=min(min_left,p[r-L]);
if (p[r]-min_left>=0) return 1;
}
return 0;
}
double solve(){
while (r-l>e){
double mid=(l+r)/2;
if (check(mid)==true) l=mid;
else r=mid;
}
return r;
}
int main(){
//输入省略
printf("%d\n",int(solve()*1000));
}
G. 金银岛
题目描述
某天KID利用飞行器飞到了一个金银岛上,上面有许多珍贵的金属,KID虽然更喜欢各种宝石的艺术品,可是也不拒绝这样珍贵的金属。但是他只带着一个口袋,口袋至多只能装重量为w的物品。岛上金属有s个种类, 每种金属重量不同,分别为n1,n2,…,ns,同时每个种类的金属总的价值也不同,分别为v1,v2,…,vs。KID想一次带走价值尽可能多的金属,问他最多能带走价值多少的金属。注意到金属是可以被任意分割的,并且金属的价值和其重量成正比。
输入格式
第1行是测试数据的组数k,后面跟着k组输入。
每组测试数据占3行,第1行是一个正整数w(1≤w≤10000),表示口袋承重上限。第2行是一个正整数s(1≤s≤100),表示金属种类。第3行有2s个正整数,分别为n1,v1,n2,v2,…,ns,vs分别为第一种,第二种,…,第s种金属的总重量和总价值(1≤ni≤10000,1≤vi≤10000)。
输出格式
k行,每行输出对应一个输入。输出应精确到小数点后2位。
样例输入
2
50
4
10 100 50 30 7 34 87 100
10000
5
1 43 43 323 35 45 43 54 87 43
样例输出
171.93
508.00
这道题没啥好说的,结构体跑过去的,AC核心代码:
struct Node{
long long n,v;
double pj;
}z[105];
bool cmp(Node x,Node y){
if(x.pj!=y.pj) return x.pj>y.pj;
return x.n>y.n;
}
int main(){
//输入省略
for(int i=1;i<=k;i++){
ans=0.0;
for(int j=1;j<=100;j++) z[j].n=z[j].v=z[j].pj=0.0;
//输入省略
for(int j=1;j<=s;j++){
//输入省略
z[j].pj=z[j].v*1.0/z[j].n;
}
sort(z+1,z+s+1,cmp);
for(int j=1;j<=s;j++){
if(z[j].n>=w){
ans+=w*z[j].pj;
break;
}
else{
ans+=z[j].v;
w-=z[j].n;
}
}
//输出省略
}
}
这就是寒假一期集训的总结了,根本不想等着半个月后的二期