20200525日常摸鱼

20200525日常摸鱼

共计8题,有点少
今日训练时长:未定

洛谷P1638 逛画展
先从1开始读入数据,直到画家数量达到m的时候,便可以开始真正的处理,首先设置左端点l=1,右端点r=第一次满画家的位置,同时b数组用来存储这一段画家各出现了多少次,桶排的思想,然后判断左端点的点出现次数是否>1,假如大于1的话就可以删去,直到左端点无法再删除,这时比较下l,r和q,w,取最短的区间保存,然后每次r++,都重复进行上面的操作,判断左端点能否删,并取最短区间,这题就做完了

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=1000005;
const int inf=0x3f3f3f3f;
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
// head
set<int> s1;
int a[maxn];
int b[maxn];
int n,m;
int main()
{
 cin>>n>>m;
 rep(i,1,n+1)
 {
  cin>>a[i];
 }
 int l=1,r=0;
 int q=1,w=0;
 while(r<n)
 {
  s1.insert(a[++r]);
  b[a[r]]++;
  if(s1.size()==m)
  break;
 }
 while(b[a[l]]>1)
 {
  
  b[a[l]]--;
  l++;
 }
 q=l,w=r;
 while(r<n)
 {
  b[a[++r]]++;
  while(b[a[l]]>1)
  {
   b[a[l]]--;
   l++;
  }
  if(r-l<w-q)
  {
   q=l,w=r;
  }
 }
 cout<<q<<" "<<w<<"\n";
 return 0;
} 

P1714 切蛋糕
第一眼,找连续的区间,长度为k,最大值,甚至不是环形,这不是傻逼题吗,
然后写了个这个

rep(i,1,n+1)
 {
  b[i]+=b[i-1]+a[i];
  if(i>=m)
  {
 	maxx=max(maxx,b[i]-b[i-m]);
  }
 }

然后发现样例二都过不去,才发现是区间长度<=k都可,又改成了这样

rep(i,1,n+1)
 {
  b[i]+=b[i-1]+a[i];
  if(i>=m)
  {
   for(int j=i-m;j<i;j++)
   maxx=max(maxx,b[i]-b[j]);
  }
 }

再一想,这复杂度炸了,那么咋优化呢,哦对,这不就是长度为k的区间,找到一个最小值吗?单调队列呀(滑动窗口),然后去找了下我的单调队列模板(555,我忘了咋写了),然后就过了,哦对,以及因为我是用前缀和处理的,所以m需要+1,才能减到最远的那个数字

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=500005;
const int inf=0x3f3f3f3f;
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// head
int n,m;
ll a[maxn];
ll b[maxn];
ll loc[maxn];
ll maxx=0;
int main()
{
 iossync
 cin>>n>>m;
 rep(i,1,n+1)
 {
  cin>>a[i];
 }
 rep(i,1,n+1)
 {
  b[i]+=b[i-1]+a[i];
//  if(i>=m)
//  {
//   for(int j=i-m;j<i;j++)
//   maxx=max(maxx,b[i]-b[j]);
//  }
 }
 int head=1,tail=1;
 loc[head]=1;
 m++;
 rep(i,1,n+1)
 {
  if(loc[head]<=i-m)
  {
   head++;
  }
  while(tail>=head && b[loc[tail]]>=b[i])
  tail--;
  loc[++tail]=i;
  if(i>=m)
  {
   maxx=max(maxx,b[i]-b[loc[head]]);
  }
 }
 cout<<maxx<<"\n";
 return 0;
}

P3865 【模板】ST表
ST表模板题,我跟着oiwiki学的,套一下模板过去了,以及这题读入的数据非常恐怖,强制快读,5555

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
const int maxn=100005;
const int LOG=21;//2*10^9
int f[maxn][LOG];
int logn[maxn];
int n,m,l,r;
void init()
{
 logn[1]=0;
 logn[2]=1;
 rep(i,3,maxn)
 {
  logn[i]=logn[i/2]+1;
 }
}
inline int read()
{
 int x=0,f=1;char ch=getchar();
 while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
 while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
 return x*f;
}
int main()
{
 ios::sync_with_stdio(false);
 cin.tie(0);
 cout.tie(0);
// cin>>n>>m;
// scanf("%d %d",&n,&m);
 n=read(),m=read();
 rep(i,1,n+1)
 {
//  cin>>f[i][0]; 
//  scanf("%d",&f[i][0]);
  f[i][0]=read();
 }
 init();//预处理log,防止太慢了
// rep(i,0,LOG)//10^9
 rep(j,1,LOG)
 {
//  rep(j,1,n-(1<<j)+1+1)
  rep(i,1,n-(1<<j)+1+1)
  //原型//for (int i = 1; i + (1 << j) - 1 <= n; i++)
  {
   f[i][j]=max(f[i][j-1] ,f[i+(1<<(j-1))][j-1]);
  }
 }
 rep(i,0,m)
 {
//  cin>>l>>r;
//  scanf("%d %d",&l,&r);
  l=read(),r=read();
  int s=logn[r-l+1];//区间长度 
//  cout<<max(f[l][s],f[r-(1<<s)+1][s])<<"\n";
  printf("%d\n",max(f[l][s],f[r-(1<<s)+1][s]));
 }
 return 0;
}
// 

P1816 忠诚
emmm,其实,跟上面那题,只要把max改成min,就好了,话说加个#define max min是不是就行

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
const int maxn=100005;
const int LOG=21;//2*10^9
int f[maxn][LOG];
int logn[maxn];
int n,m,l,r;
void init()
{
 logn[0]=0;
 logn[1]=0;
 logn[2]=1;
 rep(i,3,maxn)
 {
  logn[i]=logn[i/2]+1;
 }
}
int main()
{
 ios::sync_with_stdio(false);
 cin.tie(0);
 cout.tie(0);
 cin>>n>>m;
 rep(i,1,n+1)
 cin>>f[i][0];
 init();
 rep(j,1,LOG)
 {
  rep(i,1,n-(1<<j)+2)
  {
   f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
  }
 }
 rep(i,0,m)
 {
  cin>>l>>r;
  int s=logn[r-l+1];
  cout<<min(f[l][s],f[r-(1<<s)+1][s])<<" ";
 }
 return 0;
}

P1138 第k小整数
学会了unique,把没出现过的数字往前提, 这个网站写的就很详细unique用法
以及这题也可用unique传送门

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=100005;
const int inf=0x3f3f3f3f;
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// head
int n,k;
int a[maxn];
int main()
{
 cin>>n>>k;
 rep(i,0,n)
 {
  cin>>a[i];
 }
 sort(a,a+n);
 int ans=unique(a,a+n)-a;
 if(ans>=k)
 {
  cout<<a[k-1];
 }
 else
 cout<<"NO RESULT\n";
 return 0;
}

P1102 A-B 数对
题解很多是用map和hash写的,emmmm,说实话我都没想到,用的sort和lower_bound与upper_bound

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
const int maxn=200005;
typedef long long ll;
ll a[maxn];
ll n,c,sum;
int main()
{
 cin>>n>>c;
 rep(i,0,n)
 {
  cin>>a[i];
 }
 sort(a,a+n);
 rep(i,0,n)
 {
  ll qwe=upper_bound(a,a+n,a[i]+c)-lower_bound(a,a+n,a[i]+c);
  ll asd=upper_bound(a,a+n,a[i])-a-i;
//  sum+=upper_bound(a,a+n,a[i]+c)-lower_bound(a,a+n,a[i]+c);
  sum+=asd*qwe;
  i=upper_bound(a,a+n,a[i])-a-1;
 }
 cout<<sum<<"\n";
 return 0;
}

P1419 寻找段落
二分平均值,前缀和处理,每次判断能否匹配,同时加入单调队列优化处理

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=100005;
const int inf=0x3f3f3f3f;
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// head
int a[maxn];
db b[maxn];
int n,s,t;
int loc[maxn];
bool check(double x)
{
// ms(b,0,sizeof(b)
 rep(i,1,n+1)
 {
  b[i]=b[i-1]+a[i]-x;
 }
 int head=0,tail=0;
 loc[head]=1;
 rep(i,s,n+1)
 {
  if(loc[head]<i-t)
  head++;
  while(tail>=head && b[loc[tail]]>b[i-s])
  tail--;
  loc[++tail]=i-s;
  if(b[i]-b[loc[head]]>=0)
  return 1;
 }
 return 0;
}
int main()
{
 cin>>n>>s>>t;
 rep(i,1,n+1)
 cin>>a[i];
 double l=-10000,r=10000,mid;
 while(r-l>0.000001)
 {
  mid=(l+r)/2;
  if(check(mid))
  l=mid;
  else
  r=mid;
 }
// cout<<l<<"\n";
 printf("%.3lf\n",l);
 return 0;
}

P3124 [USACO15OPEN]Trapped in the Haybales S
这题的输入简直有病,先介绍距离和大小,结果先输入大小,再输入距离,以及翻译有点小瑕疵
直接把我卡死

简单就是分左右边,先sort一下,然后找到左边第一个不可能突破的点,然后找右边最小加固的,然后再找到右边第一个不可能突破的点,然后找左边最小加固的,两遍循环

#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
typedef long long ll;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
const int inf=0x3f3f3f3f;
ll b[maxn],n,m,r,l;
pair<ll,ll> a[maxn];
int main()
{
 cin>>n>>m;
 rep(i,0,n)
 {
  cin>>a[i].second>>a[i].first;
  a[i].first-=m;
 }
 sort(a,a+n);
 int flag=-1;
 rep(i,0,n-1)
 {
  if(a[i].first<0 && a[i+1].first>0)
  {
   flag=i;
   break;
  }
 }
 if(flag==-1)
 {
  cout<<"-1\n";
  return 0;
 }
 ll ans=9999999999999;
 ll asd=ans;
 r=flag+1;
 for(int i=flag;i>=0;i--)
 {
  while(r<n && a[r].first-a[i].first>a[r].second)
  {
   r++;
  }
  if(r>=n)
  break;
  ans=min(ans,a[r].first-a[i].first-a[i].second);
 }
 l=flag;
 for(int i=flag+1;i<n;i++)
 {
  while(l>=0 && a[i].first-a[l].first>a[l].second)
  {
   l--;
  }
  if(l<0)
  break;
  ans=min(ans,a[i].first-a[l].first-a[i].second);
 }
// per(i,0,flag+1)
// {
//  rep(j,flag+1,n)
//  {
//   if(a[i].second>=a[j].first-a[i].first+1)
//   {
//    if(a[j].second>=a[j].first-a[i].first+1)
//    {
//     ans=b[i]=0;
//     break;
//    }
//   }
//   else
//   {
//    b[i]=a[j].first-a[i].first+1-a[i].second;
//    ans=min(b[i],ans);
//    break;
//   }
//  }
//  if(ans==0)
//  break;
// }
 if(ans==asd)
 cout<<"-1\n";
 else
 cout<<max(ans,0ll)<<"\n";
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值