2021暑假集训--简单数据结构


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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值