学习笔记19:牛客寒假训练营(DFHJK)

D

数组长度为2*1e5 ,我们知道如果超过30个非(-1,1)的数字相乘一定是大于查询的值域的

所以如果超过60(30*2)个数字,那么一定不能构成查询的数,而如果小于60个则可以暴力预处理一下,求出并记录,每个值变化时数组的乘积,在查询中直接查询

需要注意的是0是一定可以达到的,只需把一个数变成0,那么数组的乘积都是0

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010;
int a[N];int n,q;
map<int,int>mp;

void solve(){
    
    cin>>n>>q;
    set<int>s;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        s.insert(a[i]);
    } 
    int t=sqrt(1e9)+1;
    if(s.size()<=60){
        for(auto c:s){
            for(int j=c-t;j<=c+t;j++){
                int res=1;
                for(int i=1;i<=n;i++){
                    res=res*(a[i]-j);
                    if(abs(res)>1e9) break;
                }
                if(abs(res)<=1e9)mp[res]=1;
            }
        }
    }
    mp[0]=1;
    int m;
    while(q--){
        cin>>m;
        if(mp.count(m)) cout<<"Yes\n";
        else cout<<"No\n";
    }
}
signed main(){
    
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
}

F

第二类斯特林数模板

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010,mod=1e9+7;
int a[N],v[N],w[N],ans[N];
int in[N],inv[N];
int n,m;
int qmi(int a,int b){
    int res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}
void inti(){
    int res=1;
    in[0]=1;
    for(int i=1;i<=N;i++){
        in[i]=(in[i-1]*i)%mod;
    }
}
void solve(){
    cin>>n>>m;
    inti();
    int ans=0;
    for(int i=0;i<=m;i++){
        ans=(ans+(qmi(-1,m-i)*qmi(i,n))%mod*qmi(in[i]*in[m-i]%mod,mod-2))%mod;
    }
    cout<<ans<<endl;
}
signed main(){
    
    int t=1;
    while(t--){
        solve();
    }
}
        

H

让我们看这样一个二进制数

10010100

我们可以O(n)求出它对应的数组的和

如何考虑更优解

我们注意到如果把最高位的1改成0,我们就可以把更低的位全部变成1

10010100 => 01111111

这么做的贡献为所有 

\sum a[i] | 01111111=01111111

减去所有\sum a[i] &10000000=10000000

这样我们可以尝试去掉每一位1,然后O(n)求一下和,取最大值即是答案

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010;
int a[N],v[N],w[N],ans[N];int n,m;
int get(int x){
    int res=0;
    for(int i=1;i<=n;i++){
        if((w[i]&x)==w[i]) res+=v[i];
    }
    return res;
}
void solve(){
    
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>v[i]>>w[i];
    } 
    int ans=get(m);
    for(int i=m;i;i-=(i&(-i))){
        ans=max(ans,get(i-1));
    }
    cout<<ans<<endl;
}
signed main(){
    
    int t=1;
    cin>>t;
    while(t--){
        solve();
    }
}
        

J

奇妙的二分

枚举最大距离

二分的过程中尝试

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010;
int a[N];

void solve(){
    int x,y,w;
    int n;
    cin>>n>>x>>y;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    auto check=[&](int d){
        int last=y;
        set<int>s;
        if(abs(x-y)<=d) s.insert(x);
        for(int i=1;i<=n;i++){
            if(s.size() &&  abs(a[i]-last)<=d) s.insert(last); 
            while(s.size() && *s.begin()<a[i]-d) s.erase(s.begin());
            while(s.size() && *s.rbegin()>a[i]+d) s.erase(*s.rbegin());
            last=a[i];
        }
        return s.size();

    };
    int l=0,r=1e9+1;
    while(l<r){
        int mid=l+r>>1;
        if(!check(mid)){
            l=mid+1;
        }else{
            r=mid;
        }
    }
    cout<<l<<endl;
}
signed main(){
    
    int t=1;
    while(t--){
        solve();
    }
}
        

K

模拟一下可知

部分题目连接在一起可以形成一个环(加上其他连向环的边形成基环树,这里如果环内确定下来,那么环外的选择就已经确定了,可以反推,所有只需要考虑环内的数量即可),如果环头和环尾不一致则不成一个方案。

我们直接从环上的点开始模拟,依次求出每个选择是否可行(根据上文的方法)

求出所有环的方案数相乘即是答案

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<map>

using namespace std;
typedef long long LL;
#define int long long
typedef pair<int,int> PII;
const int N=1000010,mod=998244353;
int a[N],d[N];
bool st[N];
string str[N];
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i]>>str[i];
        d[a[i]]++;
    }
    queue<int>q;
    for(int i=1;i<=n;i++){
        if(!d[i]) q.push(i);
    }
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=1;
        if(--d[a[t]]==0){
            q.push(a[t]);
        }
    }
    int ans=1;
    for(int i=1;i<=n;i++){
        if(st[i]) continue;
        //cout<<i<<endl;
        int res=0;
        for(int j=0;j<5;j++){
            int now=i;
            st[now]=1;
            int nowop=j;
            while(1){
                nowop=str[now][nowop]-'A';
                now=a[now];
                st[now]=1;
                if(now==i)break;
            }
            if(nowop==j)res++;
        }
        ans=(ans*res)%mod;
    }
    cout<<ans<<endl;




}
signed main(){
    
    int t=1;
    //cin>>t;
    while(t--){
        solve();
    }
}
    

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值