2021牛客暑期多校训练营1

52 篇文章 1 订阅
34 篇文章 0 订阅

A题:

枚举每个sum,i代表n,j代表m,即求出sg函数

注意:要用bitset不能用bool不然会超时

#include<iostream>
#include<string>
#include <bits/stdc++.h>
using namespace std;
const int N = 5005;
bitset<N> F[N];
void pre(){
	for(int sum=0;sum<=10000;sum++){
		for(int i=0,j=sum-i;i<=5000&&j>=0;i++,j--){
			if(!F[i][j]){
				for(int k=1;i+k<=5000;k++)
					for(int l=0;j+k*l<=5000;l++)
					F[i+k][j+k*l]=true;
				for(int k=1;j+k<=5000;k++)
					for(int l=0;i+k*l<=5000;l++)
					F[i+k*l][j+k]=true;	
			}
		}
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	pre();
	int T;
	cin>>T;
	while(T--){
		int n,m;
		cin>>n>>m;
		puts(F[n][m] ? "Alice" : "Bob");
	}
	return 0;
} 

B题:

就是找相似三角形

#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
#define ll long long

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	double r,a,b,h;
	cin>>r>>a>>b>>h;
	if(2*r<=b){
		cout<<"Drop"<<endl;
	}
	else{
		double d1=(a-b)/2;
		double d2=sqrt(h*h+d1*d1);
		double x=r*d2/h;
		double d3=a/2-x;
		double d4=d3/d1*h;
		double ans=h-d4;
		cout<<"Stuck"<<endl;
		printf("%.10lf\n",ans);
	}
	return 0;
} 

D题:

也是一道水题,找出一行中连续0的个数,若大于m则结果加上大于m的个数

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
#define ll long long
const int N = 2050;
int n,m;
int a[N][N],b[N];
string str1[N],str2;

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	for(int i=0;i<n;i++){
		cin>>str1[i];
	}
	ll ans=0;
	cin>>str2;
	for(int i=0;i<n;i++){
		int tmp=0;
		for(int j=0;j<n;j++){
			if(str1[i][j]=='0')tmp++;
			if(str1[i][j]!='0'){
			if(tmp>=m){
			ans+=(tmp-m+1);
			}
			tmp=0;
			}
		}
		if(tmp){
			if(tmp>=m){
			ans+=(tmp-m+1);
			}
			tmp=0;
		}
	}
	cout<<ans<<endl;
	return 0;
} 

E题:

BFS和模拟.

题目大意:给你一个n*m的地图,从左上角开始,走到右下角,路上有各种管子,你可以随意翻转它们,输出的时候如果不能到达那就输出NO,否则输出YES,接下来就是路径和翻转管子的角度.

思路:虽然管子有6种,但是只需要分成两种来分析,一种是拐弯的,一种是不能拐弯的,不能拐弯的保持原来的方向,拐弯的则要进行判断.

#include<bits/stdc++.h>
#define LL long long
#define dl double
#define Pi pair<int,int>
#define SZ(a) ((int)a.size())
using namespace std;
const int N = 1005;

int T;
int n,m;
int a[N][N],b[N][N];
struct node{
  int x,y,fro;
  node(){}
  node(int a,int b,int c){
    x = a;y = b;fro = c;
  }
};
//记录每个结构体前面的结构体
//即记录这一步前的一步的x,y,fro和状态.f[][][4]最后一个[4]代表的是状态意思是:
//up->0 right->1 down->2 left->3
node f[N][N][4];//up->0 right->1 down->2 left->3
queue<node>Q;

void ins(int x,int y,int fro,node k){
	//当下一部没有被遍历过时 
  if(f[x][y][fro].x == -1){
    Q.emplace(x,y,fro);
    f[x][y][fro] = k;
  }	
}

//初始化
void init(){
	for(int i = 0;i <= n + 1;i++)
     for(int j = 0;j <= m + 1;j++)
      for(int k = 0;k < 4;k++)
        f[i][j][k] = node(-1,-1,-1);
  	f[1][1][0] = node(0,0,0);
  	Q.emplace(1,1,0);//从(1,1)开始,方向为向上 
} 

void bfs(){
	init();
	while(!Q.empty()){
		auto now=Q.front(); Q.pop();
		 auto [x,y,fro] = now;//x=now.x , y=now.y , fro=now.fro 
    	if(x < 1 || x > n || y < 1 || y > m)continue;
    	//分为两种情况一种是管子是弯的(0~3) 
    if(a[x][y] <= 3){
    	//当这一步的状态是向左或者向右时,下一步能扩展向上和向下 
      if(fro & 1){
      	//向上 
        ins(x - 1,y,2,now);
        //向下 
        ins(x + 1,y,0,now);
      }
        //当这一步的状态是向上或者向下时,下一步能扩展向左和向右 
      else {
      	//向左 
        ins(x,y - 1,1,now);
        //向右 
		ins(x,y + 1,3,now);
      }
    }
    //一种的管子是直的(4~5),不管是什么情况都会保持以前的状态 
    else {
      if(fro == 0)ins(x + 1,y,fro,now);
      if(fro == 2)ins(x - 1,y,fro,now);
      if(fro == 1)ins(x,y - 1,fro,now);
      if(fro == 3)ins(x,y + 1,fro,now);
    }
	}
	int id=0;
	//没有走到达终点的情况 
	if(f[n + 1][m][id].x == -1){cout << "NO\n";return ;}  
	//以下为能走到终点的情况 
	cout << "YES\n";
	//从最后一个状态开始往前递归放进ans中 
	node now(n + 1,m,id);
	vector<vector<int>>ans;
	while(now.x != 1 || now.y != 1){
    auto [x,y,fro] = f[now.x][now.y][now.fro];
    vector<int>tmp;
    tmp.clear();tmp.push_back(0);tmp.push_back(x);
    tmp.push_back(y);ans.push_back(tmp);
    //角度判断 
    int deg = 0;
    //管子为直时 
    if(fro == now.fro){
      //fro为奇数时说明上一步为左右,那么下一步如果为上下的话角度旋转就为90 
      if((fro % 2 == 1) && a[x][y] == 5)deg = 90;
      //fro为偶数时说明上一步为上下,那么下一步如果为左右的话角度旋转就为90 
      if((fro % 2 == 0) && a[x][y] == 4)deg = 90;
    }
    //管子为弯时 
    else {
      int ned = 0;
      //下一步为上的话判断上一步是否为右,是的话那么ned=2,否则ned=3 
      if(now.fro == 0)ned = (fro == 1 ? 2 : 3);
      //略 
      if(now.fro == 2)ned = (fro == 1 ? 1 : 0);
      if(now.fro == 1)ned = (fro == 0 ? 0 : 3);
      if(now.fro == 3)ned = (fro == 0 ? 1 : 2);
      deg = (ned - a[x][y] + 4) % 4 * 90;
    }
    tmp.clear();
    tmp.push_back(1);
    tmp.push_back(deg);
    tmp.push_back(x);
    tmp.push_back(y);
    ans.push_back(tmp);
    now = f[now.x][now.y][now.fro];//迭代,上一步等于下一步 
 	}
 	memset(b,0,sizeof(b));
	  //对ans里面储存的数据进行输出 
	  for(int i = SZ(ans) - 1;i >= 0;i--)
	    if(ans[i][0] == 1){
	      ans[i][1] = (ans[i][1] - b[ans[i][2]][ans[i][3]] + 360) % 360;
	      b[ans[i][2]][ans[i][3]] = (b[ans[i][2]][ans[i][3]] + ans[i][1]) % 360;
	    }
	  int cnt = 0;
	  for(int i = 0;i < SZ(ans);i++){
	    if(ans[i][0] == 1){
	      if(ans[i][1] != 0)cnt++;
	    }
	    else cnt++;
	  }
	  cout << cnt << endl;
	  for(int i = SZ(ans) - 1;i >= 0;i--){
	    if(ans[i][0] == 1 && ans[i][1] == 0)continue;
	    for(auto x : ans[i])cout << x << " ";
	    cout << endl;
  	}
} 
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
  while(T--){
    cin >> n >> m;
    for(int i = 1;i <= n;i++)
      for(int j = 1;j <= m;j++)
        cin >> a[i][j];
    bfs();
  }
}

F题:

找规律的一个题,不难发现100及以上都是符合要求的数.那么分为三种情况,一种是小于10,一种是大于10小于100,一种是大于100.(官方的答案是分为两种情况,小于100的直接暴力求解,但是我是分成3种,因为可以预处理一下)

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
#define ll long long

ll pre[20] = { 4,11,18,28,35,42,52,59,66,76 };
ll pre2[20] = { 0,0,1,1,1,2,2,2,3,4 };

ll fun(ll r) {
	ll ans;
	if (r <= 10) {
		if (r == 0)return 0;
		ans = pre2[r - 1];
	}
	else if (r < 100) {
		ll a = r / 10;
		ans = pre[a - 1];
		for (ll i = a * 10 + 1; i <= r; i++) {
			ll p1 = i / 10, p2 = i % 10;
			if (p1 % 3 == 0 || p2 % 3 == 0 || i % 3 == 0) {
				ans++;
			}
		}
	}
	else {
		ans = 76 + r - 100;
	}
	return ans;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	ll l, r;
	ll T;
	cin >> T;
	while (T--) {
		cin >> l >> r;
		ll ans;
		ans = fun(r) - fun(l - 1);
		cout << ans << endl;
	}
	return 0;
}

J题(没搞明白但是下面的题解写的很好):

线段树

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 1000005
#define inf 0x3f3f3f3f
#define mod 1000000007
#define rep(i,s,t) for(ll i=s;i<=t;i++)
#define dep(i,s,t) for(ll i=t;i>=s;i--)
#define s(x) scanf("%lld",&x);
#define inf 0x3f3f3f3f
#define fi first
#define se second
#define ss(x,y) scanf("%lld%lld",&x,&y)
#define sss(x,y,z) scanf("%lld%lld%lld",&x,&y,&z)
#define pii pair<ll,ll>
#define piii pair<pii,ll>
#define lson now<<1
#define rson now<<1|1
struct node{
	ll u,v;
	ll lazy_d;
	bool f;
	node(ll u,ll v,ll lazy_d,bool f):u(u),v(v),lazy_d(lazy_d),f(f){};
	node(){};
}t[N<<2];
struct node1{
	ll u,v;
}temp[N];
ll d[N],cost[N];

void pushdown(ll now)
{
    if(t[now].lazy_d)
    {
    	t[lson].u+=t[now].lazy_d,t[lson].v+=t[now].lazy_d;
    	t[rson].u+=t[now].lazy_d,t[rson].v+=t[now].lazy_d;
    	t[lson].lazy_d+=t[now].lazy_d;
    	t[rson].lazy_d+=t[now].lazy_d;
    	t[now].lazy_d=0;
    }
}

void pushup(ll now)
{
	t[now].u=max(t[lson].u,t[rson].u);
	t[now].v=min(t[lson].v,t[rson].v);
	if(t[lson].u<=t[rson].v&&t[lson].f&&t[rson].f)t[now].f=true;
    else t[now].f= false;
}

void build(ll l,ll r,ll now)
{
	t[now].lazy_d=0;
	if(l==r)
	{
		t[now].u=temp[l].u+d[l];
		t[now].v=temp[l].v+d[l];
		if(t[now].u<=t[now].v)t[now].f=true;
    	else t[now].f= false;
		return;
	}
	ll mid=(l+r)>>1;
	build(l,mid,lson),build(mid+1,r,rson);
	pushup(now);
}

node check(ll l,ll r,ll now,ll L,ll R)
{
    if(l>=L&&r<=R)
    {
        return t[now];
    }
    ll mid=(l+r)>>1;
    pushdown(now);
    if(mid<L)return check(mid+1,r,rson,L,R);
    if(mid>=R)return check(l,mid,lson,L,R);
    node x=check(l,mid,lson,L,R),y=check(mid+1,r,rson,L,R),ans=node(0,0,0,0);
    ans.u=max(x.u,y.u),ans.v=min(x.v,y.v);
    if(x.f&&y.f&&y.v>=x.u)ans.f=true;
	else ans.f=false;
	return ans;
}

void query1(ll l,ll r,ll now,ll L,ll R,ll w)
{
    if(l>=L&&r<=R)
    {
    	t[now].u+=w,t[now].v+=w;
    	t[now].lazy_d+=w;
    	return ;
	}
	ll mid=(l+r)>>1;
	pushdown(now);
	if(mid>=L)query1(l,mid,lson,L,R,w);
	if(mid<R)query1(mid+1,r,rson,L,R,w);
	pushup(now);
}

void query2(ll l,ll r,ll now,ll i,ll q,ll p)
{
	if(l==i&&r==i)
	{
		t[now].u+=q;
		t[now].v+=p;
		if(t[now].u<=t[now].v)t[now].f=true;
    	else t[now].f= false;
		return;
	}
	pushdown(now);
	ll mid=(l+r)>>1;
	if(mid>=i)query2(l,mid,lson,i,q,p);
	if(mid<i)query2(mid+1,r,rson,i,q,p);
	pushup(now);
}
void solve()
{
		ll n,m,x,L,R,i,w,q,p;
		s(n);
		rep(i,1,n)s(temp[i].u);
		rep(i,1,n)s(temp[i].v);
		rep(i,1,n-1)s(cost[i]);
		d[n]=0;
		dep(i,1,n-1)d[i]=d[i+1]+cost[i];
		build(1,n,1);
		s(m);
		while(m--)
		{
            s(x);
            if(x==0)
            {
                ss(L,R);
                node ans=check(1,n,1,L,R);
				if(ans.f)printf("Yes\n");
				else printf("No\n");
            }
            if(x==1)
            {
				ss(i,w);
				query1(1,n,1,1,i,w-cost[i]);
				cost[i]=w;
            }
            if(x==2)
            {
            	sss(i,q,p);
            	query2(1,n,1,i,q-temp[i].u,p-temp[i].v);
            	temp[i].u=q;
				temp[i].v=p;
			}
		}
 }
int main()
{
	ll T;
	s(T);
	while(T--)
	{
		solve(); 
	 } 
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值