2024牛客暑期多校第三场

目录

A-Bridging the Gap 2

B-Crash Test

D-Dominoes!

E-Malfunctioning Typewriter

H-Rectangle Intersection

J-Rigged Games

L-Sudoku and Minesweeper


A-Bridging the Gap 2

考虑船上至少L个人,每次相当于向左转移(R-L)个人,一共需要(n-l)/(r-l)次向左,需要向右(n-l)/(r-l)-1次,一共需要l*((n-l)/(r-l)-1)次,计算出每个人能贡献的向左的次数,累加看看是否大于等于需要的总次数,但可能某些人体力过大,记得取min

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef  long long ll;
const int N = 1e6+10;

int a[N];
void solve(){
    int sum=0;
    int n,l,r;
    cin>>n>>l>>r;
    int res;
    if((n-l)%(r-l)==0){
        res=(n-l)/(r-l);
    }else{
        res=(n-l)/(r-l)+1;
    }
//    cout<<res<<'\n';
//    res=(res-1)*l;
    int ans=(res-1)*l;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n;i++){
        a[i]=(a[i]-1)/2;
        sum+=min(a[i],res-1);
    }
    if(sum>=ans)cout<<"Yes"<<'\n';
    else cout<<"No"<<'\n';
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
//    cin>>T;
    while(T--)solve();

    return 0;
}

B-Crash Test

取个gcd即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef  long long ll;
const int N = 1e6+10;


void solve(){
    int n,m;
    cin>>n>>m;
    int g=-1;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        if(g==-1)g=x;
        else g=__gcd(g,x);
    }
    int ans=m%g;
    ans=min(ans,g-ans);
    cout<<ans;
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
//    cin>>T;
    while(T--)solve();

    return 0;
}

D-Dominoes!

如果一个数字出现了超过 n + 2次,一定无解

容易看出来如果左右都不同很容易构造(左右交换即可)

将所有 xi = yi的骨牌按照每个点数的出现次数放在一个堆中,每次选择 出现次数最大(且和上一个放置的不同)的骨牌放在右侧。 如果发现剩下的 xi = yi的骨牌点数都和上一个相同,不妨设该点数为 p, 从 xi ̸= yi的骨牌堆中挑一个 xi , yi ̸= p的骨牌作为间隔。

#include<bits/stdc++.h>

using namespace std;
#define int long long
typedef long long ll;
const int N = 2e5 + 10;

int n, sn = 0;

stack<pair<int, int>> b1;
map<int, int> m,mp;

void solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int u, v;
        cin >> u >> v;
        if (u == v) {
            m[u]++;

        } else {
            b1.emplace(u, v);
        }
        mp[u]++;
        mp[v]++;
        if(mp[u]>n+1||mp[v]>n+1){
            cout<<"No"<<'\n';
            return;
        }
    }
    cout<<"Yes"<<'\n';
    priority_queue<pair<int, int>> q;
    for (auto [x, y]: m) {
        q.push({y, x});
    }
    while (q.size() >= 2) {
        auto c1 = q.top();
        q.pop();
        auto c2 = q.top();
        q.pop();
        b1.push({c1.second, c2.second});
        sn++;
        if (c1.first > 1)q.push({c1.first - 1, c1.second});
        if (c2.first > 1)q.push({c2.first - 1, c2.second});
    }

    pair<int, int> sa = {0, 0};
    if (!q.empty())sa = q.top();


    int now = -1;
    while (!b1.empty() || (now != sa.second && sa.first)) {
        if (now != sa.second && sa.first) {
            cout<<sa.second<<" "<<sa.second<<'\n';
            sa.first--;
            now = sa.second;
        }else{
            pair<int, int> cur = b1.top();
            b1.pop();
            int x = cur.first, y = cur.second;
            if (x == now)swap(x, y);
            if (sn) {
                sn--;
                cout<<x<<" "<<x<<'\n';
                cout<<y<<" "<<y<<'\n';
            } else {
                cout<<x<<" "<<y<<'\n';
            }
            now = y;
        }

    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
//    cin>>T;
    while (T--)solve();

    return 0;
}

E-Malfunctioning Typewriter

跑一个字典树,n个串都得出现一次,相当于每个结点都会跑过对应的次数,每个节点对答案的贡献是独立的,相当于是它的左右儿子的01的个数对应的概率,这个概率可以预处理出来。

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 2e6 + 100;
const int mod = 1000000007;
const int INF = 0x3f3f3f3f;

int n,m;
double p ;

double f[2020][2020];
int tire[N][3];
int tot =0 ;
int siz[N];

void insert(string s){
    int id = 0 ;
    for(int i=0;i<s.size();i++){
        int val =s[i]-'0';
        if(tire[id][val] ==0 ){
            tire[id][val] = ++tot;
        }
        id = tire[id][val];
        siz[id]++;
    }
}
double ans ;
void dfs(int p){

    int siz1 = siz[tire[p][1]],siz0=siz[tire[p][0]];
    ans *= (f[siz1][siz0]);

    if(siz1)dfs(tire[p][1]);
    if(siz0)dfs(tire[p][0]);
}

void solve() {
    cin>>n>>m>>p;

    f[0][0] = 1;
    for(int i=1;i<=n;i++){
        f[i][0] = f[i-1][0] * p;
        f[0][i] = f[0][i-1]* p;
    }
    for(int i=1;i<=n;i++){

        for(int j=1;j<=n;j++){
            f[i][j] = max((p)*f[i-1][j] + (1-p)*f[i][j-1] ,(1-p)*f[i-1][j] + (p)*f[i][j-1] );
        }
    }

    ans = 1;
    for(int i=1;i<=n;i++){
        string s;
        cin>>s;
        insert(s);
    }

    dfs(0);
    cout<<fixed<<setprecision(12)<<ans<<endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
//    cin >> t;
    while (t--) solve();

    return 0;
}

H-Rectangle Intersection

对于每一个方格,它所在的最小的交集是它上下左右离它最近的矩形包围而成的,但暴力时间不够。

可以发现一整块的这种贡献,是可以用它所在的交集的一个角来代替的,可以用前缀和的思想,找到这些边界点求答案。

0123分别表示上下左右

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e3+50;
int s[4][N][N];
int n,m,k,lx,ly,rx,ry;
int ans=1e15;
void solve(){
    cin>>n>>m>>k;
    for(int i=0;i<=k;i++){
    	if(i==0) lx=1,ly=1,rx=n,ry=m;
		else cin>>lx>>ly>>rx>>ry;
    	s[0][lx][ry]++,s[0][rx+1][ry]--;
    	s[1][lx][ly]++,s[1][rx+1][ly]--;
    	s[2][lx][ly]++,s[2][lx][ry+1]--;
    	s[3][rx][ly]++,s[3][rx][ry+1]--;
	}
	for(int i=0;i<=1;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=m;k++)
				s[i][j][k]+=s[i][j-1][k];
    for(int i=2;i<=3;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=m;k++)
				s[i][j][k]+=s[i][j][k-1];

	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(s[1][i][j]&&s[2][i][j]){
				int x=i,y=j;
				int len1=1,len2=1;
				while(!s[0][i][y]) y++,len1++;
				while(!s[3][x][j]) x++,len2++;
				ans=min(ans,len1*len2);
			}
		}
	}
	cout<<ans;
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int _=1;
//    cin>>_;
    while(_--)
    solve();
    return 0;
}

J-Rigged Games

先处理出从每一个点开始,下一次赢下一个小局是在哪个点,(可以双指针O(n),赛时用二分多了个log)然后用倍增+二分求出答案,赛时这里二分的是跳几次,其实去算什么时候达到B的话也可以不用二分(类似于LCA时先跨大步后跨小步的做法)

多了两个二分的代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef  long long ll;
const int N = 1e6+10;

string s;
int sum1[N],sum0[N];
int a[N][25],b[N][25];

int n,aa,bb;
int  check(int k,int x){
    int res=0;
    for(int i=0;i<=20;i++){
        if((x>>i)&1){
            res+=b[k][i];
            k=a[k][i];
        }
    }
    if(res>=bb)return 1;
    else if((x-res>=bb))return 0;
    else return -1;
}
void solve(){

    cin>>n>>aa>>bb;
    cin>>s;
    string tt=s;
    while(s.size()< n+3*aa+1){
        s=s+s;
    }
    sum1[0]=sum0[0]=0;
    for(int i=0;i<s.size();i++){
        sum1[i+1] =sum1[i];
        sum0[i+1]=sum0[i];
        if(s[i]=='0')sum0[i+1]++;
        else sum1[i+1]++;
//        if(i<=20)cout<<i<<' '<<sum0[i]<<'\n';
    }
    for(int i= 1;i<= n;i++){
//    cout<<"sum0"<<sum0[i]<<endl;
        int l = i  ,r = (int)s.size();

        while(l<=r){
            int mid =(l+r)/2;
            int y1 = sum1[mid] -sum1[i-1];
            int y0 = sum0[mid] -sum0[i-1];

            if(y1>=aa ||y0>=aa)r=mid-1;
            else l =mid+1;
        }
        a[i][0] = (l)%n+1 ;

        int y1 = sum1[l] - sum1[i-1];
//        int y0 = sum0[l] -sum0[i-1];
//        cout<<i<<" "<<l<<':'<<y1<<' '<<sum0[l]<<' '<<sum0[i-1]<<'\n';
        if(y1>=aa)b[i][0]=1;
    }

        for(int i=1; i<=20; i++){
            for (int j = 1; j <= n; j++) {
            a[j][i]=a[a[j][i-1]][i-1];
            b[j][i]=b[j][i-1]+b[a[j][i-1]][i-1];
        }
    }
    for(int i=1;i<=n;i++){
        int l=bb,r=2*bb,mid;
        while(l<=r){
            mid=(l+r)/2;
            if(check(i,mid)!=-1)r=mid-1;
            else l=mid+1;
        }
        cout<<check(i,l);
    }


}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T=1;
//    cin>>T;
    while(T--)solve();

    return 0;
}

L-Sudoku and Minesweeper

找个不在边界的8就好了

#include<bits/stdc++.h>
#define int long long
using namespace std;
int mp[100][100];
string s;
int x,y;
void solve(){
	for(int i=1;i<=9;i++){
		cin>>s;
		for(int j=1;j<=9;j++){
			mp[i][j]=s[j-1]-'0';
		}
	}
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			if(mp[i][j]==8&&i<=6&&i>=4&&j<=6&&j>=4){
				x=i,y=j;
				break;
			}
		}
	}
	for(int i=1;i<=9;i++){
		for(int j=1;j<=9;j++){
			if(i==x&&j==y) cout<<8;
			else cout<<'*';
		}
		cout<<'\n';
	}
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int _ = 1;
//	cin >> _;
	while (_--) solve();
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心刍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值