week 1

  • 订单编号

    题目意思:

    如果该数出现过:寻找大于他的未出现过的数

    !留意:a[i]的范围比较大【可能考虑用离散化】

    !如果直接模拟时间复杂度过大

    !考虑用其他方式储存:将未使用过的数看作一个区间:区间的合并/区间拆分

    • 区间合并:考虑用并查集【每次合并a[i]与a[i]+1】fa[a[i]]=a[i]+1 此时fa[i]就是答案
    • 区间拆分:先寻找到可能需要被拆分的区间 进行判断
#include<iostream>
using namespace std;
int n;
//维护区间
set<pair<int,int> > s;
//保证左大右小:按照右侧端点排序
void add(int x,int y)
{
	if(x>y) return;
	s.push_back(make_pair(y,x));
}
int main()
{
	scanf("%d",&n);
    //一开始区间范围为整个数值大小
	s.add(make_pair(2e9,1));
	for(int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
        //更新区间
		auto it= lower_bound(make_pair(x,0));//寻找右端点大于他的最大值
        //其实就是寻找可能要被拆分的区间
        
		if(it->second<=x)
		{
			cout<<x<<" ";
            //需要区间被拆开
			s.insert(it->second,x-1);
			s.insert(x+1,it->first);
			s.erase(it);
		}
		else
		{
			//直接插入新的区间//此时旧区间的最左端则为最小的数值
            cout<<it->second<<" ";
			s.insert(it->second+1,it->first);
			s.erase(it);
		}
	}
	return 0;
}
//未用map离散化的并查集版本
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
int fa[maxn];
int a[maxn];
int get(int x)
{
	if(fa[x]==0) fa[x]=x;
    //初始化
	return fa[x]==x?x:(fa[x]=get(fa[x]));
}
void add(int x,int y)
{
	x=get(x);y=get(y);
	if(x==y) return;
	if(x>y) swap(x,y);
	fa[x]=y;
}
int main()
{
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		cin>>a[i];
        //读取最右端的端点
		a[i]=get(a[i]);
        //合并端点
		add(a[i],a[i]+1);
	}
	
	for(int i=1;i<=n;i++) cout<<a[i]<<" ";
}
}
  • 特殊的正方形

    • 思路一:一行一行的分析 分奇偶项【比较麻烦】

    • 思路二:按照题目要求 判断是第几圈就看距离边界的最短距离

      #include<iostream>
      using namespace std;
      char jud(int x)
      {
      	if(x%2==1) return '+';
      	else return '.';
      }
      int main()
      {
      	int n;cin>>n;
      	int k=0;
      	char a[200][200];
      	for(int i=1;i<=n/2;i++)
      	{
      		for(int j=1;j<=i;j++)
      		{
      			a[i][j]=jud(j);
      		}
      		for(int j=1;j<=n/2;j++)
      		{
      			if(j<=i) a[i][j]=jud(j);
      			else if(j>=i&&j<=n/2) a[i][j]=jud(i);
      		}
      		for(int j=1;j<=n/2;j++) cout<<a[i][j];
      		if(n%2==1) 
      		{
      			cout<<jud(i);
      		}
      		for(int j=n/2;j>=1;j--) cout<<a[i][j];
      		cout<<endl;
      	}
      	if(n%2==1)
      	{
      		for(int j=1;j<=n/2+1;j++)
      		{
      			a[n/2+1][j]=jud(j);
      		}
      		for(int j=1;j<=n/2;j++)
      		{
      			if(j<=n/2+1) a[n/2+1][j]=jud(j);
      			else if(j>=n/2+1&&j<=n/2) a[n/2+1][j]=jud(n/2+1);
      		}
      		for(int j=1;j<=n/2;j++) cout<<a[n/2+1][j];
      		if(n%2==1) 
      		{
      			cout<<jud(n/2+1);
      		}
      		for(int j=n/2;j>=1;j--) cout<<a[n/2+1][j];
      		cout<<endl;
      	}
      	for(int i=n/2;i>=1;i--)
      	{
      		for(int j=1;j<=n/2;j++) cout<<a[i][j];
      		if(n%2==1) 
      		{
      			cout<<jud(i);
      		}
      		for(int j=n/2;j>=1;j--) cout<<a[i][j];
      		cout<<endl;
      	}
      	return 0;
      }
      
      #include<iostream>
      using namespace std;
      int main()
      {
      	int n;
      	cin>>n;
      	for(int i=1;i<=n;i++)
      	{
      		for(int j=1;j<=n;j++)
      		{
      			int x=min(i,j);
      			x=min(x,n+1-i);
      			x=min(x,n+1-j);
      			if(x%2==1) cout<<"+";
      			else cout<<".";
      		}
      		cout<<endl;
      	}
      	return 0;
      }
      
  • 走楼梯

    • 动态规划:变形版本【与洛谷相似】

    • 多开一层 记录每一个状态最后连续2阶的个数 【0-2】

      #include<iostream>
      using namespace std;
      int main()
      {
      	int n;cin>>n;
          //记得开longlong
      	long long f[500][500]={0};
      	f[0][0]=1;
      	f[0][1]=0;
      	f[0][2]=0;
      	long long s=0;
      	for(int i=0;i<=n;i++)
      	{
      		//只走一步的转移
              for(int j=0;j<=2;j++)
      		{
      			f[i+1][0]+=f[i][j];
      		}
              //走两阶的转移【留意j=2时不可以转移】
      		for(int j=0;j<=1;j++)
      		{
      			f[i+2][j+1]+=f[i][j];
      		}
      	}
      	for(int i=0;i<3;i++) s+=f[n][i];
      	cout<<s;
      	return 0;
      }
      
  • 走路

    • dfs/bfs/动态规划
    • 考虑动态规划
#include<iostream>
using namespace std;
int main()
{
	int n,m;
	cin>>n>>m;
	int a[200]={0};int b[200]={0};
	int f[200][100010]={0};
	
	for(int i=1;i<=n;i++) cin>>a[i]>>b[i];
	f[0][0]=1;
	
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
		{
			if(f[i-1][j]==1)
			{
				if(j+a[i]<=m)
				f[i][j+a[i]]=1;
				if(j+b[i]<=m)
				f[i][j+b[i]]=1;
			}
		}
	}
	
	for(int i=0;i<=m;i++)
	{
		cout<<f[n][i];
	}
	
	return 0;
}
  • 简单分数模拟

    • 基础的模拟题

    • !!关于字符串与数字的对应:map离散化/考虑哈希表

      #include<iostream>
      using namespace std;
      string a[300];
      string b[300];
      int s[300];
      int c[300];
      int main()
      {
      	int n,m,k;
      	cin>>n>>m>>k;
      	for(int i=1;i<=n;i++) cin>>a[i];
      	for(int i=1;i<=m;i++)
      	{
      		cin>>b[i]>>s[i];
      	}
      	for(int i=1;i<=k;i++)
      	{
      		string name,pro,re;
      		cin>>name>>pro>>re;
      		if(re=="AC") {
      			for(int j=1;j<=n;j++)
      			{
      				if(a[j]==name)
      				{
      					for(int k=1;k<=m;k++)
      					{
      						if(b[k]==pro)
      						{
      							c[j]+=s[k];
      						}
      					}
      				}
      			}
      		}
      	}
      	for(int i=1;i<=n;i++)
      	{
      		cout<<a[i]<<" "<<c[i]<<endl;
      	}
      	return 0;
      }
      
  • 德州扑克

    • 模拟题:注意细节处理【可以合并的细节进行合并】

      #include<iostream>
      #include<algorithm>
      using namespace std;
      int n[6],c[6];
      int ju_ro()
      {
      	int x=c[1];
      	for(int i=1;i<=4;i++)
      	{
      		if(n[i+1]!=n[i]+1) return 0;
      		if(c[i]!=c[1]) return 0;
      	}
      	if(n[5]==14) return 1;
      	else return 2;
      }
      //这两种判断较容易出问题:留意 
      int ju_four()
      {
      	int x=n[1];int y=n[5];
      	int sum1=0;int sum2=0;
      	//1 4 4 4 4/ 2 2 2 2 3
      	for(int i=1;i<=5;i++)
      	{
      		if(n[i]==x) sum1++;
      		if(n[i]==y) sum2++;
      	}
      	if(sum1==4&&sum2==1) return 1;
      	if(sum1==1&&sum2==4) return 1;
      	return 0;
      }
      
      int ju_full()
      {
      	int x=n[1];
      	int y=n[4];
      	for(int i=1;i<=5;i++)
      	{
      		if(n[i]!=x&&n[i]!=y) return 0;
      	}
      	return 1;
      }
      int ju_flush()
      {
      	int x=c[1];
      	for(int i=1;i<=5;i++)
      	{
      		if(c[i]!=x) return 0; 
      	}
      	return 1;
      }
      int ju_str()
      {
      	for(int i=1;i<=4;i++)
      	{
      		if(n[i+1]<=n[i]) return 0;
      	}
      	return 1;
      }
      void judge()
      {
      	if(ju_ro()==1) cout<<"ROYAL FLUSH";
      	else if(ju_ro()==2) cout<<"STRAIGHT FLUSH";
      	else if(ju_four()) cout<<"FOUR OF A KIND";
      	else if(ju_full()) cout<<"FULL HOUSE";
      	else if(ju_flush()) cout<<"FLUSH";
      	else if(ju_str()) cout<<"STRAIGHT";
      	else cout<<"FOLD";
      	
      }
      int main()
      {
      	
      	for(int i=1;i<=5;i++) cin>>n[i];
      	for(int i=1;i<=5;i++) cin>>c[i];
      	judge();
      	return 0;
      }
      
  • 任务分配

    • 比较典型的动态规划:按照开始的时间进行排序

    • !!状态与之前假设不同【f[i]表示该时刻的最大收益:存在不处理任何任务的情况】

      #include<iostream>
      #include<algorithm>
      using namespace std;
      const int maxn=1e4;
      struct node{
      	int s,e,w;
      }a[maxn];
      bool cmp(const node &x,const node &y)
      {
      	return x.s<y.s;
      }
      int f[maxn];
      int main()
      {
      	int n;cin>>n;
      	for(int i=1;i<=n;i++)
      	{
      		cin>>a[i].s>>a[i].e>>a[i].w;
      	}
      	
      	sort(a+1,a+1+n,cmp);
      	
      	
      	for(int i=1;i<=1005;i++)
      	{
      		f[i+1]=max(f[i],f[i+1]);
      		//该时刻可以选择不动或者寻找起始时间与其相同的进行状态转移
      		for(int j=1;j<=n;j++)
      		{
      			if(a[j].s==i)
      			{
      				f[a[j].e]=max(f[a[j].e],f[i]+a[j].w);
      			}
      		}
      	}
      	int a=0;
      	for(int i=1;i<=1005;i++)
      	{
      		a=max(a,f[i]);
      	}
      	cout<<a;
      	return 0;
      }
      
  • 路径计数

    • bfs和dfs时间复杂度太高tle了
    • 考虑动态规划:f[i] [j]=f[i-1] [j] +f[i ] [j-1];前提是可以通行
    #include<iostream>
    using namespace std;
    int sx[4]={0,0,1,-1};
    int sy[4]={1,-1,0,0};
    long long sum=0;
    int n;
    int a[105][105];
    int s[105][105];
    const long long maxn=1e9+7;
    int main()
    {
    	
    	cin>>n;
    
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			cin>>a[i][j];
    		}
    	}
    	
    	s[1][1]=1;
    	
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=n;j++)
    		{
    			if(a[i][j])
    			{
    				if(a[i+1][j])
    				{
    					s[i+1][j]+=s[i][j];
    					s[i+1][j]%=maxn;
    				}
    				if(a[i][j+1])
    				{
    					s[i][j+1]+=s[i][j];
    					s[i][j+1]%=maxn;
    				}
    			}
    		}
    	}
    	
    	cout<<s[n][n]%maxn;
    	return 0;
    }
    
  • 最大和上升子序列

    • 与最大上升子序列不同 !不要弄混

    • 此时状态记录的是最大和

      #include<iostream>
      using namespace std;
      int main()
      {
      	int n;
      	cin>>n;
      	int f[10005]={0};
      	int a[10005];
      	for(int i=1;i<=n;i++) cin>>a[i];
      
      	for(int i=1;i<=n;i++)
      	{
      		f[i]=max(f[i],a[i]);
      		for(int j=i;j<=n;j++)
      		{
      			if(a[j]>a[i])
      			{
      				f[j]=max(f[j],f[i]+a[j]);
      			}
      		}
      	}
      	int m=0;
      	for(int i=1;i<=n;i++)
      	m=max(m,f[i]);
      	cout<<m;
      	return 0;
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值