【NEUQ第十届图灵杯题解(持续更新)】

A.有用的算法(*800)

判断两个条件是否都满足条件即可

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
	long long a[1000010];
	cin>>n;
	for(int i=1;i<=n;i++)  cin>>a[i];
	int flag1=1,flag2=1;
	for(int i=1;i<n;i++)
	{
		if(a[i]>a[i+1])
		{
			flag1=0;
			break;
		}
	}
	for(int i=1;i<n;i++)
	{
		if(a[i]<a[i+1])
		{
			flag2=0;
			break;
		}
	}
	if(flag1||flag2)  cout<<"erfen is useful!";
	else  cout<<"bukeyi";
}

B.平衡数(*800)

用字符串表示,或者计算数位和都可行

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	string s;
	cin>>t;
	while(t--)
	{
		cin>>s;
		if(s[0]-'0'+s[1]-'0'==s[2]-'0'+s[3]-'0')  cout<<"YES"<<endl;
		else  cout<<"NO"<<endl;
	}
}

C.三角形(*900)

计算几何,将要询问的点(xp,yp)的x坐标带入直线方程,如果得出的y<yp,说明点在直线之下。求出AB和BC的直线方程,带入P坐标,如果都满足上述条件,说明点在三角形内。如果yp<=0直接输出no。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	double xb,xc,yc,xp,yp;
	cin>>xb>>xc>>yc;
	cin>>xp>>yp;
	int flag1=0,flag2=0;
	if(yp<=0)
	{
		cout<<"no"<<endl;
		return 0;
	}
	double k1=yc/xc;
	if(k1*xp>yp)  flag1=1;
	double k2=yc/(xc-xb);
	if(k2*(xp-xb)>yp)  flag2=1;
	if(flag1&&flag2)  cout<<"yes"<<endl;
	else  cout<<"no"<<endl;
}

D.文稿修订(*1200)

考查:字符串的基本操作

难度不大,直接进行模拟即可,就是有点麻烦。可以用字符串的插入函数insert进行插入,会方便很多。提前记录NEUQ和小写neuq的各种形态,然后每次从字符串中截取4位,如果是一个独立的单词且是NEUQ,就insert;如果是小写,就记录答案。将更改的字符串存入vector中,最后一并输出。

#include<bits/stdc++.h>
using namespace std;
map<string,int>mp;
map<string,int>st;
vector<int>v;
vector<string>ans[100010];
int main()
{
	int res=0;
	string s,str;
	mp.clear();
	st.clear();
	st["NEUQ"]=1;
	mp["neuq"]=mp["Neuq"]=mp["nEuq"]=mp["neUq"]=mp["neuQ"]=mp["NEuq"]=mp["NeUq"]=mp["NeuQ"]=mp["nEUq"]=mp["nEuQ"]=mp["neUQ"]=mp["NEUq"]=mp["NEuQ"]=mp["NeUQ"]=mp["nEUQ"]=1;
	int cnt=0;
	while(s!="#")
	{
		cin>>s;
		char ch=getchar();
		if(s=="#")  break;
		int n=s.length();
		v.clear();
		for(int i=0;i<n;i++)
		{
			str=s.substr(i,4);
			if(s.length()==4)
			{
				if(mp[str])  res++;
				if(st[str])  s.insert(i,"WOW ");
			}
		}
		ans[cnt].push_back(s);
		if(ch=='\n')  cnt++;
	}
	cout<<res<<endl;
	for(int i=0;i<cnt;i++)
	{
		for(int j=0;j<ans[i].size();j++)
		{
			if(j==ans[i].size()-1)  cout<<ans[i][j];
			else  cout<<ans[i][j]<<" ";
		}
		if(i!=cnt-1)  cout<<endl;
	}
}

E.减肥计划(*1300)

考查:枚举,DFS

由于值域巨大,01背包并不可行。注意到n只有10个,如果进行枚举的话,最差也只有10!中情况,1s足够算完。枚举所有可能的选择物品的顺序, 可以用DFS或者全排列函数,然后对每种情况取最大值。

#include<bits/stdc++.h>
using namespace std;
int x[15],y[15],z[15],w[15];
int n,num[15],a,b,c;
int main()
{
	int ans=0,d,e,f,sum=0;
	cin>>n>>a>>b>>c;
	for(int i=1;i<=n;i++)  cin>>x[i]>>y[i]>>z[i]>>w[i];
	for(int i=1;i<=n;i++)  num[i]=i;
	do{
		d=0,e=0,f=0,sum=0;
		for(int i=1;i<=n;i++)
		{
			d+=x[num[i]],e+=y[num[i]],f+=z[num[i]];
			if(d>a||e>b||f>c)  break;
			sum+=w[num[i]];
		}
		ans=max(ans,sum);
	}while(next_permutation(num+1,num+n+1));
	cout<<ans;
}

F.吃包子(*1200)

考查:前缀和,双指针

其实和acwing上的最长不包含重复数的连续区间很相近,稍稍修改一下就行了。不过由于每次输出的是肉包子的数量,即区间内1的个数,还需要提前处理一下区间前缀和。

#include<bits/stdc++.h>
using namespace std;
int mp[2];
int main()
{
	int n,m,a[1000010],s[1000010];
	mp[0]=mp[1]=0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
	s[0]=0;
	for(int i=1;i<=n;i++)  s[i]=s[i-1]+a[i];
	int i=1,j=1,ans=0;
	for(i=1,j=1;i<=n;i++)
	{
		mp[a[i]]++;
		while(mp[0]>m)
		{
			mp[a[j]]--;
			j++;
		}
		ans=max(ans,s[i]-s[j-1]);
	}
	cout<<ans;
}

G.数字鉴定(*1400)

考查:差分,预处理

第一步要做的就是区间合并,因为在本题我们只需要进行查询操作,只需要对在区间的数打上标记就可以了,对一个范围内的所有数做标记,我们自然会想到差分,而且本题甚至不需要构建差分数组,直接在范围内随便加一个数就可以算作标记。

第二步就是进行预处理,我们可以直接对2~1e6中所有的数依次记录它们的倍数(1一定不满足要求,剩下的数直接暴力算,大概要算12970034次,不会超时),如果这个数的倍数在区间内,就打上标记。这样预处理完之后,我们就可以做到在O(1)的时间复杂度下进行查询。

由于暴力预处理之后运行时间会比较吃紧,需要尽可能地优化输入和输出。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,q,l,r,x;
int st[N],b[N],query[N];
void add(int l,int r)
{
	b[l]+=1;
	b[r+1]-=1;
}
void judge()
{
	for(int i=2;i<=N-10;i++)
	{
		int cnt=1;
		while(i*cnt<=N-10)
		{
			if(b[i*cnt]>0)
			{
				st[i]=1;
				break;
			}
			cnt++;
		}
	}
}
int main()
{
	memset(b,0,sizeof(b));
	memset(st,0,sizeof(st));
	memset(query,0,sizeof(query));
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&l,&r);
		add(l,r);
	}
	for(int i=1;i<=N-10;i++)  b[i]+=b[i-1];
	judge();
	while(q--)
	{
		cin>>x;
		if(x==1)
		{
			printf("NO\n");
			continue;
		}
		if(st[x])  printf("NO\n");
		else  printf("YES\n");
	}
}

I.试题排版(*1400)

考查:计数类dp

可参考洛谷P1806

用f[j]表示难度总和为i时的方案数量,状态转移方程为f[j]+=f[j-i],即每次对于总和j的方案数=难度和为j-i的方案数,再加上难度为i的题目。也可以看作完全背包,因为题目的难度为不递减,可以相等的,如果将题目的难度看成背包的物品,那么物品是可以随便取的(如对于总难度为4,我们可以选择[2,2],即选择了两个难度为2的物品),所以按照完全背包的模板,j应该从i~m循环。如果题目难度只能递增,那么就是01背包,因为每个难度只可能被选到一次。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int m;
	cin>>m;
    vector<int>dp(m+1);
	dp[0]=1;
	for(int i=1;i<=m;i++)
		for(int j=i;j<=m;j++)
			dp[j]=(dp[j]+dp[j-i])%998244353;
	cout<<dp[m];
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值