文章目录
- 下午比赛题:
- T1:[937B.Vile Grasshoppers(素数判断)](https://codeforces.com/problemset/problem/937/B)
- T2:[930A.Peculiar apple-tree(树的宽度) ](https://vjudge.net/problem/CodeForces-930A)
- T3:[1385D.a-Good String(dfs)](https://codeforces.com/problemset/problem/1385/D)
- T4:[371C.Hamburgers(二分答案)](https://codeforces.com/problemset/problem/371/C)
- T5:[1278B.A and B(找规律)](https://codeforces.com/problemset/problem/1278/B)
- 练习题:
下午比赛题:
T1:937B.Vile Grasshoppers(素数判断)
题意:给你两个数p,y,求去掉2-y中所有2-p的数的倍数后剩下的最大值,如果没有剩下数输出-1.
分析:从y开始倒序遍历每一个整数i,只要不含有2到p中的因子(不能被2到p中的数整除),就可以作为答案输出
和筛法一个意思,注意最大值可以逆向枚举.只要算到sqrt(10^9)(i<=p这个条件的加入是为了防止x可能不是素数,但是x不含有2~p之间的任何一个因数)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll p,y;
bool check(ll x){
if(x<2) return false;
for(ll i=2;i<=x/i && i<=p;i++){
if(x%i==0){
return false;
}
}
return 1;
}
int main(){
cin>>p>>y;
for(ll i=y;i>p;i--){
if(check(i)){
cout<<i<<endl;
return 0;
}
}
cout<<-1<<endl;
}
T2:930A.Peculiar apple-tree(树的宽度)
总结:dfs或者bfs统计树的每一层的宽度,是奇数ans+1,是偶数,ans不变
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
vector<int> v[N];
int ceng[200000];
int n;
void dfs(int u,int ii){//dfs统计树的宽度,u表示节点编号,ii表示层数
ceng[ii]++;
for(int i=0;i<v[u].size();i++){
dfs(v[u][i],ii+1);
}
}
int main(){
cin>>n;
for(int i=2;i<=n;i++){
int tmp;
cin>>tmp;
v[tmp].push_back(i);
}
int ans=0;
dfs(1,1);
for(int i=1;i<=n;i++){
if(ceng[i]%2==0) ceng[i]=0;
else ceng[i]=1;
ans+=ceng[i];
}
cout<<ans<<endl;
}
T3:1385D.a-Good String(dfs)
分析:dfs中做决策,枚举状态
#include<bits/stdc++.h>
using namespace std;
int ff(string str,char ch){//把str全变成ch
int cnt=0;
for(int i=0;i<str.size();i++){
if(str[i]!=ch) cnt++;
}
return cnt;
}
int dfs(string str,char ch){//带返回值的dfs函数,返回对str的最小操作次数
if(str.length()==1){
if(str[0]==ch) return 0;
return 1;
}
int len=str.size();
string s1=str.substr(0,len/2);
string s2=str.substr(len/2,len/2);
int cnt1=ff(s1,ch);//把前半段变成ch
int cnt2=ff(s2,ch);//把后半段变成ch
int q1=dfs(s2,ch+1);//把后半段变成ch+1串
int q2=dfs(s1,ch+1);//把前半段变成ch+1串
return min(q1+cnt1,q2+cnt2);
}
int main(){
int t;
cin>>t;
string s;
while(t--){
int n;
cin>>n>>s;
cout<<dfs(s,'a')<<endl;
}
}
T4:371C.Hamburgers(二分答案)
分析:二分答案 ,原因是答案具有单调性,比最优解小的值都满足,我们需要找的是断点的最右边(参考算法基础课)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string s;
ll b,S,c;
ll m;
ll nb,ns,nc,pb,ps,pc;
bool check(ll mid){
ll sum=0;
if(mid*b>nb) sum+=pb*(mid*b-nb);//mid*b >nb时,说明当前储量不够,否则的话是不用买的,sum会变成负值!!
if(mid*S>ns) sum+=ps*(mid*S-ns);
if(mid*c>nc) sum+=pc*(mid*c-nc);
return sum<=m;
}
int main(){
cin>>s;
cin>>nb>>ns>>nc>>pb>>ps>>pc;
cin>>m;
ll l=0,r=1e13;
for(int i=0;i<s.length();i++){
if(s[i]=='S') S++;
else if(s[i]=='B') b++;
else if(s[i]=='C') c++;
}
while(l<r){
ll mid=(l+r+1)>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
cout<<l;
}
T5:1278B.A and B(找规律)
分析:
设detla为两数之差的绝对值,现在问题可以转化为1 2 3 4 5 …中间插入+或者-,枚举操作次数,
例如当操作次数为3时
-1-2-3=-6
1-2-3=-4
…-2 0 2 …4…6
观察上面的规律,1到n的所有符号组合中,会涉及到从最大值依次往下-2,正负都有
我们需要做的就是计算(1+n)*n/2的值是否大于等于detla,然后判断他俩的奇偶性是否相同
Code:
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int a,b;
cin>>a>>b;
int detla=abs(a-b);
int ans=0;
for(ans=0;;ans++){
int Max=ans*(ans+1)/2;
if(Max>=detla && Max %2 ==detla %2){
break;
}
}
cout<<ans<<endl;
}
}
练习题:
T1:1463B.Find The Array(构造)
样例:
input
4
5
1 2 3 4 5
2
4 6
2
1 1000000000
6
3 4 8 1 2 3
output
3 3 3 3 3
3 6
1 1000000000
4 4 8 1 3 3
分析:可以考虑将每一个a[i]
变为离它最近的2的整数次幂,如8变为4,10变为9,这样可以保证每个数的变化量都小于等于
a
[
i
]
/
2
a[i]/2
a[i]/2,故最终总的变化量不会大于
s
/
2
s/2
s/2
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=55;
ll a[N];
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++) {
ll x;
cin>>x;
ll tmp=(ll)(log(x)/log(2));
a[i]=(ll)pow(2,tmp);
}
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}
cout<<"\n";
}
}
语法知识点复习:
exp(n)
值为e^n
次方;
另外log函数包括两种函数 一种以e为低的log()函数
另一种为以10为底的log 10()函数;
另外如果自定义以m为底,求log n的值
需要double a=log(n)/log(m);
T2:1461B.Find the Spruce(递推)
题目大意:给定一个n*m大小的网格,从中找出每个点能拓展出的云杉木图案的个数,累加求和
分析:
暴力做会导致超时,所以此题可以观察性质采用递推,设f[i][j]
为每个点能拓展出的树木,它的值应该等于下面三个的最小值+1
从下往上走,每当碰到一棵云杉点的时候这个点就是它下面三个点的最小值 +1,如果不是云杉点,那么就要
将这个点的值设为0,因此还需要一个整数数组用来统计。
#include<bits/stdc++.h>
using namespace std;
char g[505][505];
int f[505][505];
int n,m;
int check(int i,int j){
if(g[i][j]=='.') return 0;
if(i==n-1 || j==0 || j==m-1) return 1;
int minn=0x3f3f3f3f;
for(int k=j-1;k<=j+1;k++){
minn=min(minn,f[i+1][k]+1);
}
return minn;
}
int main(){
int t;
cin>>t;
while(t--){
memset(f,0,sizeof f);
cin>>n>>m;
for(int i=0;i<n;i++) cin>>g[i];
int res=0;
for(int i=n-1;i>=0;i--){
for(int j=0;j<m;j++){
if(g[i][j]=='*'){
f[i][j]=check(i,j);
res+=f[i][j];
}
}
}
cout<<res<<endl;
}
}