2024牛客多校第七場

liyishui發表於2024-08-08

K

貪心地先湊出前後端後,中間的部分是本質不同的子序列個數

然後列舉可以重疊的部分,如果可以重疊肯定是迴文字尾

有不少細節,比如空串,重疊部分要求後面的能取到

#include<cstdio>
#include<iostream>
#define int long long 
#define ULL unsigned long long
using namespace std;
const int P=1e9+7;
const int N=1e6+505;
const int K=97;
int n,m,res;
int dp[N],last[N];
ULL pre[N],suf[N],pow[N];
string s,t; 
int check(int x){
    return pre[x]==suf[x];
}
signed main(){
    cin >> n >> m;
    cin >> s >> t;
    s=' '+s+' ';
    t=' '+t+' ';
    int l=1,r=n;
    pow[0]=1;
    for (int i=1;i<=m;i++)
        pow[i]=pow[i-1]*K;
    for (int i=m;i>=1;i--){
        pre[i]=pre[i+1]*K+(t[i]-'a');
        suf[i]=suf[i+1]+pow[m-i]*(t[i]-'a');
    }
        
    for (int i=1;i<=m;i++){
        while(l<=n&&s[l]!=t[i]) l++;
        //if (l>n) break;
        l++;        
    }
    for (int i=1;i<=m;i++){
        if (l<=r+1) res+=check(i);
        while(r>0&&s[r]!=t[i]) r--;
        //if (r<=0) break;
        r--;
    }
    if (l<=r){
        dp[l-1]=1;
        for (int i=l;i<=r;i++){
            if (last[s[i]]) dp[i]=(dp[i-1]*2-dp[last[s[i]]-1]+P)%P;
                else dp[i]=dp[i-1]*2%P;
            last[s[i]]=i;        
        }

        res=(res+dp[r])%P;    
    }
    if (r==l-1) res=(res+1)%P;
    cout << res << endl;
    return 0;
}

J

考慮極限的情況,最極限就是兩端能否掃到

沒想到極限的話就可能要算不等式

#include<bits/stdc++.h>
using namespace std;

inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
void Kafka()
{
    int l=read(),x=read(),y=read();
    if(1LL*x*x+1LL*y*y<=1LL*l*l) printf("Yes\n0\n");
    else if(1LL*(l-x)*(l-x)+1LL*y*y<=1LL*l*l) printf("Yes\n%d\n",l);
    else puts("No");    
}
signed main()
{
    for(int T=read();T--;) Kafka();
    return 0;
}

I

首先可以二分列舉,初始機器n越多,最後能造成的傷害越多

肯定是先造新的機器,直到不能再造,然後全都拿去打擊怪物

造新的機器這個問題就轉化成:

給定n,每次用m個換新的k個,最後能換出多少個。

可以寫出遞推式子f(n)=f(n-m+k)+m,可以把-m+k寫成-c

等價為f(n)=f(n-c)+m=f(n-2c)+2m=...

但是不能直接把n減到小於c,因為要滿足先夠-m然後再+k,這裡就特判一下

#include<bits/stdc++.h>
using namespace std;

inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
#define int long long
int m,k,h;
int check(int n,int h){
    if(n<m){
        if(n<h) return 0;
        else return 1;
    }
    int c=m-k;
    int sum=((n-m)/c+1)*m;
    sum+=(n-m)%c+k;
    if(sum>=h) return 1;
    else return 0;
}
void solve(){
    cin>>m>>k>>h;
    if(h==0) {
        cout<<0<<"\n";
        return;
    }
    if(k==m){
        if(m-1>=h) {
            cout<<h<<"\n";
        }
        else cout<<m<<"\n";
    }
    else {
        int l=0,r=h,ans=-1;
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(mid,h)){
                ans=mid;
                r=mid-1;
            }
            else l=mid+1;
        }
        cout<<ans<<"\n";
    }
}
signed main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

D

隊友用一種神奇的雜湊過了

把所有數出現的次數雜湊

原本雜湊字串是abcdeaa,給它雜湊成一個值

同理用cnt[x]表示x出現的次數,cnt[1]cnt[2]cnt[3]..cnt[n],給它雜湊成一個值

則在i這個位置時,能匹配得上的一定是之前位置雜湊值也一樣的數

但是有一個問題!!

能匹配得上的位置也可能是k的倍數,所以再用一個雙指標維護一下

#include<bits/stdc++.h>
#define int long long
using namespace std;
const __int128 P=1000000000000000003;
const int N=2e5+505;
inline int read()
{
    int x=0;bool f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-');
    for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    return f?x:-x;
}
int n,k,m;
int a[N],h[N],dp[N];
__int128 hs[N];
map<int,int> f,g;
struct lst{
    vector<int> c,d;
    int n,t,i=1;
    int sum=0;
    void init(int _n,int _t){
        n=_n;
        t=_t;
        c.resize(n+5);
        d.resize(n+5);
    }
    void next(){
        int p=a[i];
        c[p]++;
        d[p]++;
        if (t==-1) g[sum]+=t;
        sum=(sum+hs[p])%P;
        //printf("p=%lld\n",p);
        if (d[p]==k){
            d[p]=0;
            sum=(sum-hs[p]*k%P+P)%P;
        }
        if (t==1) g[sum]+=t;
        i++;
    }
};
void test(){
    for (int i=0;i<=n;i++)
        printf("a[%lld]=%lld\n",i,a[i]);
    for (int i=1;i<=n;i++)
        cout << (long long)hs[i] << endl;
}
void test_map(){
    for (auto i=g.begin();i!=g.end();i++){
        printf("%lld %lld\n",i->first,i->second);
    }
}
void work(){
    n=read(); k=read();
    for (int i=1;i<=n;i++)
        a[i]=read();
    f.clear(); g.clear(); 
    
    for (int i=1;i<=n;i++)
        f[a[i]]=0;
    m=0;
    for (auto i=f.begin();i!=f.end();i++)
        i->second=++m;
    
    for (int i=1;i<=n;i++)
        a[i]=f[a[i]];
    lst p,q;
    p.init(n,1);
    q.init(n,-1);
    int res=0;
    //test();
    g[0]=1;
    for (int i=1;i<=n;i++){
        int pos=a[i];
        p.next();
        while(p.c[pos]-q.c[pos]>k){
            q.next();
            //printf("%lld %lld q.i=%lld\n",p.c[pos],q.c[pos],q.i);
        }
        
        res+=g[p.sum]-1;
        //printf("add %lld:%lld %lld\n",i,g[p.sum]-1,p.sum);
        //test_map();
        //printf("p.i=%lld q.i=%lld\n",p.i,q.i);
    }
    
    
    cout << res << endl;
}
signed main()
{
    hs[0]=0;
    hs[1]=1;
    for (int i=2;i<N;i++){
        hs[i]=hs[i-1]*N%P;
    }
    int T;
    T=read();
    while(T--) work();
    return 0;
}

相關文章