2022牛客寒假算法基础集训营3(补题)

按照出题人认为的难度顺序排序

A - 智乃的Hello XXXX

思路: 签到。

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    cout<<"hello chino"<<'\n';
	return 0;
}

os:一开始没看这个题以为这次比赛也不会有这种签到题,先看了看别的,结果一刷新已经上千人做完了这个了hhhhhh

D - 智乃的01串打乱

思路:签到, 从头开始遍历字符串,找到某个0和某个1,交换即可。

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
string s;
int a,b,len;

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    cin>>len;
	cin>>s;
    for(int i=0;i<len;i++)
    {
    	if(a==0||b==0) 
    	{
    		if(s[i]=='0') a=i;
    	    else if(s[i]=='1') b=i;
		}
    	else break;
	}
	swap(s[a],s[b]);
	cout<<s<<'\n';
	return 0;
}

os:一开始想写找到第一个0和第一个1来着,结果写着写着发现找的不是第一个0和1,不过不重要hhh,swap()函数对于字符串处理之前用过,特别good!

B - 智乃买瓜

 思路:01背包DP,注意分情况讨论,f[i][j]表示到第i个瓜可以凑够j元的种类,j>a[i]和j=a[i]分别有两种情况,注意区分。

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=1e3+5;
int n,m,a[N];
ll f[N],res1,res2,res;

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
    	for(int j=m;j>=1;j--)
    	{
    		f[j]=f[j]%mod;
    		if(j==a[i]/2) f[j]=(f[j]+1)%mod;
    		if(j<a[i]&&j>a[i]/2) f[j]=(f[j]%mod+f[j-a[i]/2]%mod)%mod;
    		if(j==a[i])
			{
				f[j]=(f[j]+1)%mod;
				f[j]=(f[j]%mod+f[j-a[i]/2]%mod)%mod;
			} 
    		if(j>a[i])
			{
				if(f[j-a[i]]!=0)
				res1=f[j-a[i]]%mod;
				else res1=0;
				if(f[j-a[i]/2]!=0)
				res2=f[j-a[i]/2]%mod;
				else res2=0;
				res=(res1%mod+res2%mod)%mod;
				f[j]=(f[j]%mod+res%mod)%mod;
			} 
		}
	}
	for(int i=1;i<=m;i++)
	cout<<f[i]<<" \n"[i==m];
	return 0;
}

os:代码一维优化了一波。当时做这个题的时候因为这两个有两种情况的范围卡了好久好久

I - 智乃的密码

思路:尺取法应用,注意尺取法写法。

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=1e5+5;
int a[N],cnt[10],n,L,R;
char s[N];
  
int find(char c)
{
    if('a'<=c&&c<='z') return 1;
    if('A'<=c&&c<='Z') return 2;
    if('0'<=c&&c<='9') return 3;
    return 4;
}
int pan()
{
    int tot=0;
    for(int i=1;i<=4;i++)
    {
    	if(cnt[i]) tot++;
	}
    return tot;
}
  
int main()
{
    cin>>n>>L>>R;
    scanf("%s",s);
    for(int i=0;i<n;i++) a[i]=find(s[i]);
    ll ans=0;
    for(int i=0,j=0;i<n;i++)
    {
        while(j<=n&&pan()<3)//找到第一个满足条件的值,固定右端点
        {
            if(j<n) cnt[a[j]]++;
            j++;
        }
        int l=max(j,L+i);//max,min函数确保满足长度要求
        int r=min(n,i+R);
        ans+=max(0,r-l+1);
        cnt[a[i]]--;
    }
    cout<<ans<<'\n';
    return 0;
}

L - 智乃的数据库

 思路:模拟题,map套vector用法。

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=1e3+5;
int n,m;
int g[N*2][N];
string s[N],ss;

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    cin>>n>>m;
    for(int i=1;i<=m;i++) cin>>s[i];
    for(int i=1;i<=n;i++)
    {
    	for(int j=1;j<=m;j++)
        cin>>g[i][j];
	}
	getchar();
	getline(cin,ss);//读入一行字符(包括空格)
	int len=ss.length();
	vector<string>ves;
	for(int i=0;i<len;i++)//截取分类关键词
	{
		if(ss[i]==','||ss[i]==';')
		{
			string t="";
			int j=i;
			while(1)
			{
				j--;
				if(ss[j]==' '||ss[j]==',') break;
				t+=ss[j];
			}
			reverse(t.begin(),t.end());
			ves.push_back(t);
		}
	}
	vector<int>vei;
	len=ves.size();
	for(int i=0;i<len;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(ves[i]==s[j]) vei.push_back(j);
		}
	}
	sort(vei.begin(),vei.end());//vector内也可以排序
	map<vector<int>,int>mp;
	len=vei.size();
	for(int i=1;i<=n;i++)
	{
		vector<int>vec;
		for(int j=0;j<len;j++)
		{
			vec.push_back(g[i][vei[j]]);
		}
		mp[vec]++;
	}
	cout<<mp.size()<<'\n';
	for(auto&t:mp)//输出,之前我经常用迭代器,这样也可以
	{
		cout<<t.second<<' ';
	}
	return 0;
}

os:第一次用STL嵌套,,,涨知识了

E - 智乃的数字积木(easy version)

 思路:未改变染色前,只能改变相邻的相同颜色区域,所以ans1为把原相连相同颜色的色块从大到小排序;看到数据范围,染色处理就用暴力染色,后再与得到ans1一样处理即可得到ans2。

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=1e5+5;
int n,m,k,u,v;
int col[N];
char s[N];

ll cut()
{
	for(int l=1,r=1;l<=n;l=r+1,r=l)//数组切段写法
	{
		while(r<n&&col[r+1]==col[l]) r++;
		sort(s+l,s+1+r,[](const char&A,const char&B) 
		{
            return A>B;//排序,cmp函数不是多次使用可以这样写
        });
	}
	ll res=0;
	for(int i=1;i<=n;i++)
	{
		res=res*10+(s[i]-'0');
		res%=mod;
	}
	return res;
}

void pan(int a,int b)
{
	for(int i=1;i<=n;i++)
	{
		if(col[i]==a)col[i]=b;
	}
	return;
}

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++) scanf("%d",&col[i]);
    printf("%lld\n",cut());
    while(k--)
    {
    	scanf("%d%d",&u,&v);
    	pan(u,v);
    	printf("%lld\n",cut());
	}
	return 0;
}

os:一开始看这个题的时候读错题了

C - 智乃买瓜(another version)

 思路:在easy version中,转化方程为dp[i][j]=dp[i−1][j−wi​]+dp[i−1][j−wi/2​​]+dp[i−1][j],这个题很显然是它的逆过程,那么转化方程就是dp[i][j]=dp[i+1][j]−dp[i][j−wi​]−dp[i][j−wi/2​​],vector的用处是对于可能取一半瓜的情况直接得到原来瓜的重量,然后在dp数组中减去该重量瓜对于所有情况的影响,而这两个步骤必是同时进行的。

 AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=1e3+5;
int m;
ll f[N]; 

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    cin>>m;
    f[0]=1;
    vector<int>vec;
	for(int i=1;i<=m;i++) cin>>f[i];
	for(int i=1;i<=m;i++)
	{
		while(f[i])
		{
			vec.push_back(i*2);
			for(int j=0;j<=m;j++)
			{
				if(j+i<=m) f[j+i]-=f[j];
				while(j+i<=m&&f[j+i]<0) f[j+i]+=mod;
				if(j+i*2<=m) f[j+i*2]-=f[j];
				while(j+i*2<=m&&f[j+i*2]<0) f[j+i*2]+=mod;
			}
		}
	}
	cout<<vec.size()<<'\n';
	for(int i=0;i<vec.size();i++)
	printf("%d%c",vec[i]," \n"[i+1==vec.size()]);//写法可以学习
	return 0;
}

os:vector使用还是挺方便的,尤其是这种未知规模的数据。

G - 智乃的树旋转

 思路:首先读清题意,树旋转就是父子关系的改变,原来的父节点变成了原来子节点的子节点,这里使用结构体和结构体指针的一点知识。建立两棵二叉树,遍历节点,父子关系不同的就是旋转节点。

 AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
const int N=1e3+5;
int n,ra,rt;

struct tree
{
	int fa,ch[2];
} t[N],a[N];

int build(tree*t,int n)
{
	int x,y;
	vector<bool>v(n+1,true);
	for(int i=1;i<=n;i++)
	{
		cin>>x>>y;
		v[x]=v[y]=false;
		t[i].ch[0]=x;
		t[i].ch[1]=y;
		if(x) t[x].fa=i;
		if(y) t[y].fa=i;
	}
	for(int i=1;i<=n;i++)
	if(v[i]) return i;
	return -1;
}

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    cin>>n;
    ra=build(a,n);
    rt=build(t,n);
    for(int i=1;i<=n;i++)
    {
    	for(int j=1;j<=n;j++)
    	{
    		if(t[i].fa==j&&a[j].fa==i)
    		{
    			cout<<"1"<<'\n';
    			cout<<i<<'\n';
    			return 0;//在某些代码中,return 0的位置可以很灵活
			}
		}
	}
	cout<<"0"<<'\n';
	return 0;
}

J - 智乃的C语言模除方程

思路: 建模过程的学习。标解:

 

AC代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define INF 0x3f3f3f3f
//判断是否需要开ll!!!
//判断是否需要初始化!!!
const int mod=1e9+7;
ll P,r,l,L,R,ans;

ll calx(ll x,ll y)
{
	x=min(P-1,x);
	ll round=(y+1)/P;
	ll last=(y+1)%P;
	return (x+1)*round+min(last,x+1)-1;
}

ll cal(ll l,ll r,ll L,ll R)
{
	return calx(r,R)-calx(l-1,R)-calx(r,L-1)+calx(l-1,L-1);
}

int main()
{
//	freopen("test.in","r",stdin);
//  freopen("output.in", "w", stdout);
    cin>>P>>l>>r>>L>>R;
    P=abs(P);
    if(l<=0&&0<=r)
    {
    	ll base=((ll)1e10)/P*P;
    	ans+=(base+R)/P-(base+L-1)/P;
	}
	if(R>0&&r>0)
	ans+=cal(max(1ll,l),r,max(1ll,L),R);
	if(L<0&&l<0)
	ans+=cal(max(1ll,-r),-l,max(1ll,-R),-L);
	cout<<ans<<'\n';
	return 0;
}

os:建模过程是问题转化的过程吧,这个题中模除倒不是一个重点去处理,而是如何求这个个数。

若有错误请指教orz

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值