博客总结第十周+牛客月赛
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了博客总结第十周+牛客月赛相关的知识,希望对你有一定的参考价值。
P1873 [COCI 2011/2012 #5] EKO / 砍树
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int a[maxn];
int n,m;
int main()
{
cin>>n>>m;
int l=0,r=0,mid;
for(int i=1;i<=n;i++){
cin>>a[i];
r=max(r,a[i]);
}
while(l<=r)
{
mid=(l+r)/2;
ll s=0;
for(int i=1;i<=n;i++)
if(a[i]>mid)
s+=a[i]-mid;
if(s<m)
r=mid-1;
else
l=mid+1;
}
cout<<r<<endl;
return 0;
}
P1024 [NOIP2001 提高组] 一元三次方程求解
在二分中,一个题目关键部分对了,就算一些细节的地方处理的不好,也能ac。
#include <bits/stdc++.h>
using namespace std;
double a,b,c,d;
double cir(double x)
{
return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
cin>>a>>b>>c>>d;
double l,r,x1,x2,mid;
int s=0;
for(int i=-100;i<100;i++)
{
l=i;r=i+1;
x1=cir(l);x2=cir(r);
if(!x1)
{
printf("%.2f ",l);
s++;
}
if(x1*x2<0)
{
while(l+0.001<=r)
{
mid=(l+r)/2;
if(cir(mid)*cir(r)<0)
l=mid;
else
r=mid;
}
printf("%.2f ",l);
s++;
}
if(s==3) break;
}
return 0;
}
B. Odd Grasshopper
一道分奇偶的水题,找清除规律就好。
#include <bits/stdc++.h>
using namespace std;
long long x,n;
int main()
{
freopen("in.txt","r",stdin);
int t;cin>>t;
while(t--)
{
long long ans;
cin>>x>>n;
if(x%2==0)
{
if(n%4==1)
ans=x-n;
else if(n%4==2)
ans=x+1;
else if(n%4==3)
ans=x+n+1;
else
ans=x;
}
else
{
if(n%4==1)
ans=x+n;
else if(n%4==2)
ans=x-1;
else if(n%4==3)
ans=x-(n+1);
else
ans=x;
}
cout<<ans<<endl;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int a[maxn];
int main()
{
freopen("in.txt","r",stdin);
int t;cin>>t;
while(t--)
{
int n;cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
if(n==1){
cout<<a[1]<<endl;
continue;
}
sort(a+1,a+n+1);
int ans=-INT_MAX;
for(int i=2;i<=n;i++)
{
ans=max(ans,a[i]-a[i-1]);
}
ans=max(a[1],ans);
cout<<ans<<endl;
}
return 0;
}
*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
牛客 分组
还好最近看了一点二分。
刚开始想用map来做的,结果发现map的遍历不太会,索性又开了个数组直接记录。二分对边数据的临界值要好好考虑,一般会没输出,或者答案大于1或者小于1,本题我慢慢试出来了,没太多想。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;
int a[maxn];
int b[maxn];
int go(int mid)
{
int ans=0;
for(int i=1;i<=n;i++)
{
if(b[i])
{
if(b[i]%mid==0)
ans+=b[i]/mid;
else
ans+=b[i]/mid+1;
}
}
if(ans<=m) return 1;
else return 0;
}
int main()
{
//freopen("in.txt","r",stdin);
cin>>n>>m;
int ans=1;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[a[i]]++;
}
int k=1;
sort(a+1,a+n+1);
for(int i=2;i<=n;i++)
{
if(a[i]!=a[i-1])
k++;
}
int l=0,r=n+1;
if(k<=m)
{
while(l<r)
{
int mid=(l+r)/2;
if(go(mid))
r=mid;
else
l=mid+1;
}
cout<<r<<endl;
}
else
{
cout<<-1<<endl;
}
return 0;
}
受不了了这一题,明明不难,可就是通不过。刚开始题意理解不了,然后有把规律找错,最后每次都超时,换了快读,还是超时,最后才发现必须要用printf进行输出。蠢的呀!
A—数字游戏
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
string calc(int x)
{
if(x == 0) return "0";
string ans = "";
while(x){
ans += ('0' + x % 2);
x >>= 1;
}
reverse(ans.begin(), ans.end());
return ans;
}
ll read()
{
char c=getchar();
ll ds=0,fs=1;
while (c<'0'||'9'<c) {if (c=='-') fs=-1;c=getchar();}
while (c>='0'&&c<='9') ds=(ds<<3)+(ds<<1)+c-48,c=getchar();
return ds*fs;
}
int main()
{
int t;cin>>t;
while(t--)
{
ll x,ans=0;
x=read();
string s=calc(x);
for(int i=0;i<s.length();i++)
{
if(s[i]=='1')
ans++;
}
int k=s.length()-1;
if(x%2)
{
if(ans%2)
ans=2*ans-1;
else
ans=2*ans-2;
}
else
{
if(ans%2)
ans=2*ans+1;
else
ans=2*ans;
}
printf("%d\\n",ans);
}
return 0;
}
B.跳跳跳
常规的区间dp,如果我还是去年刚学完区间dp的水平,肯定能很快做出来。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4005;
int n,a[maxn],f[maxn][maxn];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
a[n+i]=a[i];
}
for(int i=1;i<=2*n;i++) //默认为第一次跳跃
{
f[i][i]=a[i]*1;
}
for(int len=2;len<=n;len++) //跳跃次数
{
for(int i=1,j=i+len-1;j<=2*n;i++,j++)
{
f[i][j]=max(f[i+1][j]+len*a[i],f[i][j-1]+len*a[j]);
}
}
int ans=0;
for(int i=1;i<=n;i++)
{
ans=max(ans,f[i][i+n-1]);
}
cout<<ans<<endl;
return 0;
}
C 数字匹配
1.首先判断出2000以内的双重for循环不会超时
2.关键在于掌握substr从下标为i的位置开始截取j位。双重for循环找到即返回1。
#include <bits/stdc++.h>
using namespace std;
int n,k;
string calc(int x)
{
if(x == 0) return "0";
string ans = "";
while(x){
ans += ('0' + x % 2); //转换类型
x >>= 1;
}
reverse(ans.begin(), ans.end());
return ans;
}
int check(int x,int y)
{
string s=calc(x);
string t=calc(y);
int s1 = s.size();
int s2 = t.size();
//substr用法: s.substr(i,j)表示从下标为i的位置开始截取j位
for (int i = 0; i + k <= s1; ++i)
for (int j = 0; j + k <= s2; ++j)
if (s.substr(i, k) == t.substr(j, k))
return 1;
return 0;
}
int main()
{
cin>>n>>k;
int ans=0;
for(int i=1;i<n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(check(i,j))
ans++;
}
}
cout<<ans<<endl;
return 0;
}
I 体操队形
(第一次坐到全排列的题目,根本没想到这个方法)
将b数组进行全排列,再用vis数组进行标记1(本质就是确定这个数能不能放在这个位置上),一组数没有被重复标记,则成立。
#include <bits/stdc++.h>
using namespace std;
int n;
int a[15],b[15],vis[15];
int main()
{
cin>>n;
int total=1,ans=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
b[i]=i;
total*=i;
}
for(int i=1;i<=total;i++)
{
int f=0;
memset以上是关于博客总结第十周+牛客月赛的主要内容,如果未能解决你的问题,请参考以下文章