2023牛客暑期多校训练营4

A.Bobo String Construction

s取全0串或者全1串,至少有一者满足题述条件

大致感受一下

随便举几个例子:

t s t

0000|0000|0000 s为全0不符合,但s为全1符合

1001|00|1001 s为全0不符合,但s为全1符合

101|000000|101 s为全0或为全1均符合

所以只需判断全0串或者全1串哪个符合题述条件即可(只要判断一方即可,一方不符合就是另一方)

 

 

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
int n;
void solve() {
    cin>>n;
    string t;
    cin>>t;
    string s(n,'0');
    string ss(n,'1');
    string str=t+s+t;
    if(str.find(t,1)!=t.size()+s.size()) cout<<ss<<endl;
    else cout<<s<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

或者用kmp算法在文本串匹配模式串 

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=1010;
int ne[N];
int n;
void solve() {
    cin>>n;
    string t;
    cin>>t;
    string s(n,'0');
    string ss(n,'1');
    string str='0'+t+s+t;
    int len1=t.size();
    int len2=t.size()+n+t.size();
    t='0'+t;
    //求next值
    for(int i=2,j=0;i<=len1;i++){
        while(j&&t[i]!=t[j+1]) j=ne[j];
        if(t[i]==t[j+1]) j++;
        ne[i]=j;
    }
    //文本串匹配模式串
    bool ok=true;
    for(int i=1,j=0;i<=len2;i++){
        while(j&&str[i]!=t[j+1]) j=ne[j];
        if(str[i]==t[j+1]) j++;
        //找到了模式串
        if(j==len1){
            //i表示文本串匹配到了哪一位
            if(i!=len1&&i!=len2){
                ok=false;
                break;
            }
        }
    }
    if(ok) cout<<s<<endl;
    else cout<<ss<<endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

F.Election of the King 

先从小到大排个序,然后每次肯定要么删第一个数,要么删最后一个数

我们先求出第一个数(最小的数)和最后一个数(最大的数)的平均值x,然后求出大于x的数有几个,小于等于x的数有几个,如果大于x的数多,那么就删掉第一个数,否则就删掉最后一个数

将运行轨迹输出出来,方便检查

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<cstdio>
#define endl '\n'
//#define int long long
typedef long long ll;
using namespace std;
typedef pair<int,int>PII;
int n;
void solve()
{
    cin>>n;
    vector<PII>ans;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        ans.push_back({x,i});
    }
    sort(ans.begin(),ans.end());
    int p=0,q=n-1;
    while(p<q){
        int x=ans[p].first+ans[q].first;
        int l=p,r=q;
        while(l<r){
            int mid=(l+r)/2;
            if(ans[mid].first*2>x) r=mid;
            else l=mid+1;
        }
//        cout<<p<<" "<<q<<" "<<l<<endl;
        if(q-l+1>l-p) p++;
        else q--;
    }
    cout<<ans[p].second<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--)
    solve();
    return 0;
}

L.We are the Lights

法一:先预处理操作的行的最终状态和列的最终状态

然后按照先后顺序进行枚举,由于记录的都是最终状态,也就是说操作的每一行以及每一列都只会操作一次(不会重复操作)

如果开了一列灯,那么就加上(n-开了几行灯)

如果开了一行灯,那么就加上(m-开了几列灯)

如果关了一列灯,那么就减去开了几列灯

如果关了一行灯,那么就减去开了几列灯

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<cstdio>
#include<set>
#define endl '\n'
//#define int long long
typedef long long ll;
using namespace std;
typedef pair<int,int>PII;
const int N=1e6+10;
int n,m,q;
struct node{
    int kind;//0表示行,1表示列
    int x;
    int status;//0表示关灯,1表示开灯
}s[N];
bool st[N];
int cnt[N];
void solve()
{
    cin>>n>>m>>q;
    //预处理,记录操作的行的最终状态以及列的最终状态
    for(int i=0;i<q;i++){
        string s1,s2;
        int x;
        cin>>s1>>x>>s2;
        if(s1=="row"){
            if(s2=="on") s[i]={0,x,1};
            else s[i]={0,x,0};
        }
        else{
            if(s2=="on") s[i]={1,x,1};
            else s[i]={1,x,0};
        }
    }
    set<PII>se;
    for(int i=q-1;i>=0;i--){
        int kind=s[i].kind,x=s[i].x;
        if(!se.count({kind,x})){
            se.insert({kind,x});
            st[i]=true;
        }
    }
    ll res=0;
    for(int i=0;i<q;i++){
        if(!st[i]) continue;
        //开灯
        if(s[i].status==1){
            cnt[s[i].kind]++;//cnt[0]记录开了几行灯,cnt[1]记录开了几列灯
            if(s[i].kind==1) res+=n-cnt[0];//如果开了一列灯,那么就加上(n-开了几行灯)
            else res+=m-cnt[1];//如果开了一行灯,那么就加上(m-开了几列灯)
        }
        //关灯
        else{
            if(s[i].kind==1) res-=cnt[0];//如果关了一列灯,那么就减去开了几列灯
            else res-=cnt[1];//如果关了一行灯,那么就减去开了几列灯
        }
    }
    cout<<res<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--);
    solve();
    return 0;
}

换一种写法: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<set>
#include<cstdio>
#define endl '\n'
//#define int long long
typedef long long ll;
using namespace std;
const int N=1e6+10;
int n,m,q;
struct node{
    string s1;
    int x;
    string s2;
}s[N];
bool ok[N];
void solve()
{
    cin>>n>>m>>q;
    for(int i=0;i<q;i++) cin>>s[i].s1>>s[i].x>>s[i].s2;
    set<pair<string,int>>se;
    for(int i=q-1;i>=0;i--){
        string s1=s[i].s1;
        int x=s[i].x;
        if(!se.count({s1,x})){
            se.insert({s1,x});
            ok[i]=true;
        }
    }
    int row=0,col=0;
    ll res=0;
    for(int i=0;i<q;i++){
        if(!ok[i]) continue;
        if(s[i].s2=="on"){
            if(s[i].s1=="row"){
                res+=m-col;
                row++;
            }
            else{
                res+=n-row;
                col++;
            }
        }
        else{
            if(s[i].s1=="row") res-=col;
            else res-=row;
        }
    }
    cout<<res<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--)
    solve();
    return 0;
}

法二:

从后往前推,同理也是要知道操作的行和列的最终状态,不过呢,由于在后面的肯定是最终状态,所以当枚举到某行或某列是第一次出现时,那么就是最终状态,标记一下,如果后面再出现已经标记过的行或列时,就直接continue

我们先知道后面的状态,比如说后面的状态是对一列进行关灯操作,那么如果前一操作是开灯操作,那么它开的数量就是(n-开灯的列数),实际上根本不用管后一操作是开灯还是关灯,只要后面操作了,前一次操作操作同样的地方就白操作了,所以只要记录后面状态操作的行的次数以及操作的列的次数就行了

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<set>
#include<cstdio>
#define endl '\n'
//#define int long long
typedef long long ll;
using namespace std;
const int N=1e6+10;
int n,m,q;
struct node{
    string s1;
    int x;
    string s2;
}s[N];
int row[N];
int col[N];
void solve()
{
    cin>>n>>m>>q;
    for(int i=0;i<q;i++) cin>>s[i].s1>>s[i].x>>s[i].s2;
    int cnt1=n;//还剩几行在后面没被操作过,也就是有几行操作是有效的
    int cnt2=m;//还剩几列在后面没被操作过,也就是有几列操作是有效的
    //由于我们只要求灯亮的数量,所以我们只要知道开灯操作有哪些是有效的就行,不需要考虑关灯
    ll res=0;
    for(int i=q-1;i>=0;i--){
        int x=s[i].x;
        if(s[i].s2=="on"){
            if(s[i].s1=="row"){
                if(row[x]) continue;
                res+=cnt2;
            }
            else{
                if(col[x]) continue;
                res+=cnt1;
            }
        }
        if(!row[x]&&s[i].s1=="row") {
            row[x]=1;
            cnt1--;
        }
        else if(!col[x]&&s[i].s1=="column"){
            col[x]=1;
            cnt2--;
        }
    }
    cout<<res<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--)
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值