文章目录
A.Sliding Window
题目:传送门
可以参考这个大佬
题目大意:就是个窗口问题,移动窗口,更新数据,输入数组数据,然后输入窗口大小,分别储存最小值和最大值,然后分行输出最大值跟最小值
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cstring>
#include<cstdlib>
#define ll long long
const ll Max=1e6+5;
const ll INF=0x3f3f3f3f3f;
using namespace std;
int n,k,i,j;
int a[Max];
void getmax()
{ deque<int> s;
s.push_back(1);
for(i=2;i<=k;i++)
{
if(s.empty()||a[i]<a[s.back()])s.push_back(i);
else {while(!s.empty()&&a[i]>a[s.back()])
s.pop_back();
s.push_back(i);
}
}
printf("%d ",a[s.front()]);
for(i=k+1;i<=n;i++)
{
while(!s.empty()&&(i-s.front()>=k)) s.pop_front();
while(!s.empty()&&a[i]>a[s.back()])
s.pop_back();
s.push_back(i);
printf("%d ",a[s.front()]);
}
printf("\n");
}
void getmin()
{ deque<int> s;
s.push_back(1);
for(i=2;i<=k;i++)
{
if(s.empty()||a[i]>a[s.back()])s.push_back(i);
else {while(!s.empty()&&a[i]<a[s.back()])
s.pop_back();
s.push_back(i);
}
}
printf("%d ",a[s.front()]);
for(i=k+1;i<=n;i++)
{
while(!s.empty()&&(i-s.front()>=k)) s.pop_front();
while(!s.empty()&&a[i]<a[s.back()])
s.pop_back();
s.push_back(i);
printf("%d ",a[s.front()]);
}
printf("\n");
}
int main()
{
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++)
scanf("%d",a+i);
getmin();
getmax();
}
B.Bad Hair Day
传送门
题目大意:一群奶牛往右看,只能看到比自己小的,问一共能看到多少?
思路:维护一个单调栈或者可以转换思路,往左看有几个比自己大的,栈顶比自己小等于就出栈,否则就加上所有的,因为都比那个牛高,所以那些牛都能看到这个牛,在压入栈,具体看代码
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cstring>
#include<cstdlib>
#define ll long long
const ll Max=80050;
const ll INF=0x3f3f3f3f3f;
using namespace std;
stack <ll> s;
int main()
{
ll t,b;
cin>>t;
cin>>b;
s.push(b);
ll sum=0;
for(int i=1;i<t;i++)
{ cin>>b;
while(!s.empty()&&s.top()<=b) s.pop();
sum+=s.size();
s.push(b);
}
cout<<sum<<endl;
return 0;
}
C.Largest Rectangle in a Histogram
传送门
题目大意:给出若干矩形,求矩形一起组成的最大面积
思路:记录自己前面有多少和后面有多少
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
#include<cstdio>
#include<vector>
#define ll long long
const ll INF=0x3f3f3f3f;
const ll Max=1e5+5;
using namespace std;
ll a[Max];
ll l[Max],r[Max];
int n,i,j;
/*queue<ll> q;
stack<ll> s;
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;*/
int main()
{
while(scanf("%d",&n)&&n)
{
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
ll sum=0;
r[n]=n;
l[1]=1;
for(i=2;i<=n;i++)
{
int t=i;
while(t>1&&a[i]<=a[t-1])
t=l[t-1];
l[i]=t;
}
for(i=n-1;i>=1;i--)
{
int t=i;
while(t<n&&a[i]<=a[t+1])
t=r[t+1];
r[i]=t;
}
for(i=1;i<=n;i++)
sum=max(sum,(r[i] - l[i] + 1)*a[i]);
printf("%lld\n",sum);
}
return 0;
}
D.Max Sum of Max-K-sub-sequence
传送门
题目大意:找循环数组的最大值,并输出起始位置
思路:构造循环数组,然后就是窗口问题
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+100;
int a[maxn],sum[maxn];
deque<int>De;
int main()
{
int t,n,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i+n]=a[i];
}
De.clear();
sum[0]=0;
for(int i=1;i<=n+k-1;i++){
sum[i]=sum[i-1]+a[i];
}
int sta,en;
int ans=-1000000000;
for(int i=1;i<=n+k-1;i++){
while(!De.empty() && sum[i-1]<sum[De.back()])
De.pop_back();
while(!De.empty() && De.front()<=i-k-1)
De.pop_front();
De.push_back(i-1);
if(sum[i]-sum[De.front()]>ans){
ans=sum[i]-sum[De.front()];
sta=De.front()+1;
if(i>n)
en=i%n;
else
en=i;
}
De.push_back(i-1);
}
printf("%d %d %d\n",ans,sta,en);
}
}
E.Feel Good
可以参考传送门
F.Fence Repair
传送门
题目大意:农夫约翰为了修理栅栏,要将一块很长的木板分割成N块。准备切成的木板的长度为L1、L2、……、Ln. 未切割木板的长度恰好为切割木板的长度和。每次切断木板时,需要的开销为这块木板的长度。例如,长度为21的木板切割成5、8、8的三块木板。长为21的木板切割成13、8时,开销为21.再将长度为13的木板切割成长度5、8时,开销为13.于是合计开销为34。于是按题目要求将木板切割完,最小的开销是多少?
思路:运用优先队列,每次出来两个加和,然后再压进去,就可以保证每次都是最小,升序
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cstring>
#include<cstdlib>
#define ll long long
const ll Max=20010;
const ll INF=0x3f3f3f3f3f;
using namespace std;
int n,k,i,j;
int a[Max];
int main()
{ priority_queue<int, vector<int>, greater<int> > q;
int t;
ll sum=0;;
scanf("%d",&t);
for(i=0;i<t;i++)
{scanf("%d",&a[i]);
q.push(a[i]);}
int t1,t2,l=0;
while(q.size())
{
t1=q.top();
q.pop();
if(q.size()!=0)
{t2=q.top();
q.pop();sum+=t1+t2;
q.push(t1+t2);}
else break;
}
cout<<sum<<endl;
return 0;
}
G.Phone List
传送门
题目大意:就是你拨电话,也就是不管你是否已经输入完毕,就会尝试能否打出去,也就是某一个串不能是另一个串的前缀
思路:一种是用字典树,一种是单纯字符串比较
字符串:
#include<stdio.h>
#include<string>
#include<algorithm>
using namespace std;
string s[100001];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int a=0,n,i,j;
char w[11]={0};
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%s",&w);
s[i]=w;
}
sort(s,s+n);
for(i=1;i<n;i++)
{
if(s[i].size()>s[i-1].size())
{
for(j=0;j<s[i-1].size();j++)
if(s[i][j]!=s[i-1][j])
break;
if(j==s[i-1].size()/*返回长度*/)
a=1;
}
}
if(a) printf("NO\n");
else printf("YES\n");
}
return 0;
}
字典树:
#include <cstdlib>
#include <cstdio>
#include <cstring>
typedef struct node //节点的结构体
{
bool end;//结束的标志
int a[10];
}node;
node phonelist[100000];
int x;
int flag;
void Init()
{
flag=1;//标志
x=0; //初始位置;
for(int i=0;i<100000;i++)
{
phonelist[i].end=false;
for(int j=0;j<10;j++)
phonelist[i].a[j]=-1;
}
}
int build(char *s) //建立字典树
{
int k,now=0,tag=0;// 初始位置
int len=strlen(s);
for(int i=0;i<len;i++)
{
k=s[i]-'0';
if(phonelist[now].a[k]==-1)
{
tag=1;//说明进入一个新的位置
phonelist[now].a[k]=++x; //给数组赋值
now=x;//下一个位置
}
else
{
now=phonelist[now].a[k];
if(phonelist[now].end)
return 0; //单词的结束标志
}
}
phonelist[now].end=true; //标记结束的节点
if(!tag) return 0;
return 1;
}
int main()
{
int n,m;
char s[12];
scanf("%d",&n);
while(n--)
{
Init();
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%s",s);
if(flag)
flag=build(s);
}
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
H.Xor Sum
传送门
思路:字典树
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
#include<cstdio>
#include<vector>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const ll INF=0x3f3f3f3f;
const ll Max=3500000;
using namespace std;
int i,j,k,t,n,m,d;
/*queue<ll> q;
stack<ll> s;
//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;*/
int tree[Max][2];
int num[Max];
int x;
void Insert(int s)
{
int root=0;
for(i=31;i>=0;i--)
{
int id=(s>>i)&1;
if(tree[root][id]==0)
tree[root][id]=++x;
root=tree[root][id];
}num[root]=s;
}
int Find(int s)
{
int root=0;
for(int i=31; i>=0; i--)
{
int id=(s>>i)&1;
if(tree[root][id^1])
root=tree[root][id^1];
else
{
root=tree[root][id];
}
}
return num[root];
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(tree,0,sizeof(tree));
scanf("%d %d",&n,&m);
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
Insert(x);
}
printf("Case #%d:\n",++d);
while(m--)
{
int y;
scanf("%d",&y);
printf("%d\n",Find(y));
}
}
return 0;
}
I.Snowflake Snow Snowflakes
传送门
题目大意:是否存在循环1-n
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
#define T 15001
#define inf 0x3f3f3f3f
#define CRL(a) memset(a,0,sizeof(a))
#define mem(a,b) memset(a,b,sizeof(a))
#define so(a,b) sort(a,a+b);
#define soc(a,b) sort(a,a+b,cmp)
typedef long long ll;
struct node
{
int floor[7];
}p;
node s[T][1000];
int t[T];
bool sovle(node& a,node& b)
{
sort(a.floor,a.floor+6);
sort(b.floor,b.floor+6);
for(int i=0;i<6;++i){
if(a.floor[i]!=b.floor[i])
return false;
}
return true;
}
int main()
{
/*freopen("input.txt","r",stdin);*/
int n,i,j,k,ok;
while(~scanf("%d",&n))
{
CRL(t);ok=0;
while(n--)
{
for(i=0,k=0;i<6;++i){
scanf("%d",&p.floor[i]);
k=(k+p.floor[i])%T;
}
if(!ok){
for(i=0;i<t[k];++i){
if(sovle(p,s[k][i])){
ok=1;break;
}
}
s[k][t[k]]=p;t[k]++;
}
}
if(ok)
printf("Twin snowflakes found.\n");
else
printf("No two snowflakes are alike.\n");
}
return 0;
}