牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)
竞赛链接⬆
A题:
思路:
先构建一个string数组,将所需要匹配到的字符串作为元素,依次放入数组中,根据所需要查找字符串的个数,创建一个大循环,在创建一个指针,指向string数组中所需要比较的元素,之后再依次遍历源字符串,同时于string数组中字符串元素进行比较,当有一个字符元素匹配成功,这指向string数组元素的指针向后挪动,(巧妙解决了匹配字符串在源字符串中顺序匹配的问题,如sddfs之类),之后根据匹配结果进行输出。
代码:
时间复杂度o(n)
#include <iostream>
using namespace std;
void solve()
{
int n;
cin>>n;
string str;
cin>>str;
string a[]={"DFS","dfs"};
for(int j=0;j<2;j++)
{
int k=0;
for(int i=0;i<n;i++)
{
if(str[i]==a[j][k]) k++;
}
cout<< k/3<<' ';
}
cout<<endl;
}
int main()
{
int t;
cin>>t;
while (t--)
{
solve();
}
return 0;
}
B题:
思路:
当着火点为零的时候,最少添加为3结束。
当着火点不为零的时候,着火点只可能是0 1 2 3 这几种情况。
构造一个map将输入的着火点位置进行布尔捆绑,将每一次的着火点置为true,同时将着火点存储下来,进行遍历,由于(2,0)点的特殊性,将遍历分为两部分,即y<0与y>0 ,在遍历过程中,寻找每一个着火点距离为1的位置进行匹配,同时记录下,匹配上的(l,r),没匹配上的(l1,r1) ,遍历结束之后,开始分情况考虑,
- 左右两边都有匹配上的,
- 左边匹配上了,右边没匹配上 ,2,0处有无着火点
- 左边没匹配上,右边匹配上了 2,0处有无着火点
- 左边没匹配上 ,右边也没有匹配上, 考虑 当左边的点在1,-1时,右边点在1 ,1时
- 左边没匹配上,右边没有值,考虑左边点的位置,以及2,0出有无着火点
- 左边没值,右边没匹配上,同上,
- 当只有2,0处有值时
代码:
时间复杂度o(n)
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
const int N=1e5+10;
pair<int,long long> g[N];
map<pair<int,long long>,bool> t;
void solve()
{
t.clear();
int n;
cin>>n;
for(int i=0;i<n;i++)
{
int l;long long r;
scanf("%d %lld",&l,&r);
g[i]={l,r};
t[{l,r}]=true;
}
if(n==0) {cout<<3<<endl; return ;}
int l,r; l=r=0;
int l1,r1; l1=r1=0;
for(int i=0;i<n;i++)
{
int x=g[i].first;long long y=g[i].second;
if(y<0 && !l)
{
l1=1;
if(x==1)
if(t[{x+1,y}] || t[{x+1,y-1}] || t[{x+1,y+1}] ) l=1;
else
if(t[{x-1,y}] || t[{x-1,y-1}] || t[{x-1,y+1}] ) l=1;
}
else if(y>0 && !r)
{
r1=1;
if(x==1)
if(t[{x+1,y}] || t[{x+1,y-1}] || t[{x+1,y+1}] ) r=1;
else
if(t[{x-1,y}] || t[{x-1,y-1}] || t[{x-1,y+1}] ) r=1;
}
}
if(l && r) cout<<0<<endl;
else if(l)
{
if(r1) cout<<1<<endl;
else if(t[{2,0}]) cout<<1<<endl;
else cout<<2<<endl;
}
else if(r)
{
if(l1) cout<<1<<endl;
else if(t[{2,0}]) cout<<1<<endl;
else cout<<2<<endl;
}
else if(l1 && r1)
{
if(t[{1,-1}] && t[{1,1}]) cout<<1<<endl;
else cout<<2<<endl;
}
else if(l1)
{
if(t[{2,0}]) cout<<2<<endl;
else if(t[{1,-1}]) cout<<2<<endl;
else cout<<3<<endl;
}
else if(r1)
{
if(t[{2,0}]) cout<<2<<endl;
else if(t[{1,1}]) cout<<2<<endl;
else cout<<3<<endl;
}
else cout<<2<<endl;
}
int main()
{
int t;
cin>>t;
while (t--)
{
solve();
}
return 0;
}
C题:
思路:
本题需要考虑数值大小问题,工作人员容忍度最大为10的18次方,所以需要开long long 储存
根据题意,一个窗口,n个人,时间一直增加,所以每个人办完事的时刻,为一个前缀和
注:因为 n最大值为10的5次方,t的最大值为10的6次方,最坏情况下,10的5次方个10的6次方相加,10的11次方,所以 前缀和也需要开long long 储存
计算容忍度,可以容忍几个人增加tc个时间,也就是看它能容忍几个tc 即 q=M/tc
- 如果 q大于等于n的话,则安排鸡第一个,直接输出tc
- 如果q小于n的话,则输出n-q的前缀和
代码:
时间复杂度o(n)
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e6+10;
long long e[N];
int main()
{
long long n,q,t;
scanf("%lld%lld%lld",&n,&q,&t);
for(int i=1;i<=n;i++) scanf("%d",&e[i]);
sort(e+1,e+n+1);
for(int i=1;i<=n+1;i++) e[i]=e[i-1]+e[i];
while (q--)
{
long long r;
scanf("%lld",&r);
long long q=r/t;
if(q>=n)cout<<t<<endl;
else cout<<e[n-q]+t<<endl;
}
return 0;
}
E题:
思路:
已知 m场次的最大值为10 所以可以用dfs写
记录下每一场的选手,暴力遍历所有可能性,你只管遍历‘,剩下的交给系统
将答案ans 初始化为1号选手最差名次为 10,之后每一次场次模拟完之后,计算1号选手的名次,之后取最小值即可。
代码:
时间复杂度o(n^3)
#include <iostream>
using namespace std;
const int N=15;
int a[N];
pair<int,int> q[N];
int n,m;
int ans;
void dfs(int u)
{
if(u==m)
{
int res=1;
for(int i=1;i<n;i++)
{
if(a[i]>a[0]) res++;
}
ans=min(res,ans);
return;
}
int x=q[u].first-1,y=q[u].second-1;
a[x]+=3;
dfs(u+1);
a[x]-=3;
a[y]+=3;
dfs(u+1);
a[y]-=3;
a[x]+=1;
a[y]+=1;
dfs(u+1);
a[x]-=1;
a[y]-=1;
}
int main()
{
int t;
cin>>t;
while (t--)
{
ans=10;
cin>>n>>m;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
q[i]={a,b};
}
dfs(0);
cout<<ans<<endl;
}
return 0;
}
G题:
思路:
先将价格排序,之后将遍历,优惠求前缀和,加上本金,如果大于当前价格,则答案赋值为当前优惠和与本金,遍历结束后,输出。
注:因为要求前缀和,同样的,n最大为10的5次方m最大为10的9次方,bi最大也为10的9次方,所以需要long long 来存
代码:
时间复杂度o(n)
#include<iostream>
#include <algorithm>
using namespace std;
typedef pair <long long ,long long > PII;
const int N=1e5+10;
PII e[N];
int main()
{
int t;
cin>>t;
while (t--)
{
long long n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
{
int a,b;
cin>>a>>b;
e[i]={a,b};
}
sort(e,e+n);
long long ans=m;
long long sum=m;
for(int i=0;i<n;i++)
{
sum+=e[i].second;
if(sum>=e[i].first) ans=sum;
}
cout<<ans<<endl;
}
return 0;
}
M题:
思路:
当n能被整除时,答案为n/6;
当n不能被整除时,答案为n/6*2;
代码:
时间复杂度o(1)
#include <iostream>
using namespace std;
int main()
{
int t;
cin>>t;
while (t--)
{
int ans=0;
int n;
cin>>n;
if(n%6) ans=(n/6)*2;
else ans=n/6;
cout<<ans<<endl;
}
return 0;
}