2025“钉耙编程”中国大学生算法设计暑期联赛(3)

1. 1002 小抹爱锻炼

知识点:贪心上下界判断

计算出训练次数的下限和上限,判断M是否在上下限中即可

下限:从左到右贪心取最小=max(b[i],last)

上限:从右到左贪心取最大=min(c[i],last)

复制代码
#include<bits/stdc++.h> 
#define in inline
#define re register
#define ll long long
#define db double
#define ls(a) a<<1
#define rs(a) a<<1|1
#define sz(a) int(a.size())
#define inf 0x3f3f3f3f 
#define me(a,num) memset(a,num,sizeof(a))
#define mc(a,b) memcpy(a,b,sizeof(a))
#define For(i,a,n) for(re int (i)(a);(i)<=(n);(i)=-~(i))
#define Bor(i,n,a) for(re int (i)(n);(i)>=(a);--(i))
#define debug cout<<"QWQ"<<endl
#define Time cout<<(db)clock()/CLOCKS_PER_SEC<<endl
#define int long long
using namespace std;
const int R=1<<21,N=1e6+10;
int b[N],c[N];
in int qread()
{
    re int s=0,op=0;
    re char ch=getchar();
    while(!isdigit(ch))op|=ch=='-',ch=getchar();
    while(isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    return op?-s:s;
}
in void solve(int n,int m)
{
    int mins=0,maxs=0;
    int last=0;
    For(i,1,n)
    {
        if(b[i]>=last)
        {
            mins+=b[i];
            last=b[i];
        }
        else if(c[i]<last)
        {
            cout<<"NO"<<endl;
            return;
        }
        else
        {
            mins+=last;
        }
    }
    last=inf;
    Bor(i,n,1)
    {
        if(c[i]<=last)
        {
            maxs+=c[i];
            last=c[i];
        }
        else if(b[i]>last)
        {
            cout<<"NO"<<endl;
            return;
        }
        else
        {
            maxs+=last;
        }
    }
    if(m>maxs||m<mins)
    {
        cout<<"NO"<<endl;
        return;
    }
    else
    {
        cout<<"YES"<<endl;
        return;
    }    
}
signed main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    int T;
    T=qread();
    while(T--)
    {
        int n,m;
        n=qread(),m=qread();
        For(i,1,n)b[i]=qread();
        For(i,1,n)c[i]=qread();
        solve(n,m);
    }
    return 0;
} 

View Code


2. 1004 三带一

知识点:二分

上界S/4,二分答案,每次对13种牌各确定可用三的上下界,来确实true/false

复制代码
#include<bits/stdc++.h> 
#define in inline
#define re register
#define ll long long
#define db double
#define ls(a) a<<1
#define rs(a) a<<1|1
#define sz(a) int(a.size())
#define inf 0x3f3f3f3f 
#define me(a,num) memset(a,num,sizeof(a))
#define mc(a,b) memcpy(a,b,sizeof(a))
#define For(i,a,n) for(re int (i)(a);(i)<=(n);(i)=-~(i))
#define Bor(i,n,a) for(re int (i)(n);(i)>=(a);--(i))
#define debug cout<<"QWQ"<<endl
#define Time cout<<(db)clock()/CLOCKS_PER_SEC<<endl
using namespace std;
const int R=1<<21,N=1e6+10;
in ll qread()
{
    re ll s=0,op=0;
    re char ch=getchar();
    while(!isdigit(ch))op|=ch=='-',ch=getchar();
    while(isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    return op?-s:s;
}
struct 
{
    int maxn,lef;
}b[N];
in bool check(ll x,vector<ll>& a,ll S) {
    if (4*x>S) 
    {
        return 0;
    }
    ll totalL=0;
    ll totalR=0;
    For(i,0,12) 
    {
        ll maxR=min(x,a[i]/3);
        ll t =3*x+a[i]-S;
        ll minl=0;
        if (t>0) {minl=(t+1)/2; }//(S-mid*3)-(a[i]-3minl)>=minl
        if (minl>maxR) {return 0;}
        totalL+=minl;
        totalR+=maxR;
    }
    if (totalL<=x&&x<=totalR)
    {
        return 1;
    }
    return 0;
}
int main() 
{
    int T;
    T=qread();
    while(T--) 
    {
        vector<ll>a(13);
        ll S=0;
        For(i,0,12)a[i]=qread(),S+=a[i];

        ll Ri=S/4;
        ll Le=0;
        ll ans=0;
        while (Le<=Ri) 
        {
            ll mid=(Le+Ri)/2;
            if (check(mid,a,S)) 
            {
                ans=mid;
                Le=mid+1;
            } 
            else 
            {
                Ri=mid-1;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

View Code


3. 1007 性质不同的数字

知识点:扫描线+哈希

可以给所有的线段一个随机值,加入(l, rand_vals[i])和(r + 1, rand_vals[i]),排序,从左向右扫,通过异或来加入和删除线段,unordered_set判断扫描过程加入线段和删除线段的变化,产生新变化就count++

复制代码
#include<bits/stdc++.h> 
#define in inline
#define re register
#define ll long long
#define ull unsigned long long
#define db double
#define ls(a) a<<1
#define rs(a) a<<1|1
#define sz(a) int(a.size())
#define inf 0x3f3f3f3f 
#define me(a,num) memset(a,num,sizeof(a))
#define mc(a,b) memcpy(a,b,sizeof(a))
#define For(i,a,n) for(re int (i)(a);(i)<=(n);(i)=-~(i))
#define Bor(i,n,a) for(re int (i)(n);(i)>=(a);--(i))
#define debug cout<<"QWQ"<<endl
#define Time cout<<(db)clock()/CLOCKS_PER_SEC<<endl
using namespace std;
const int R=1<<21,N=1e6+10;
in ll qread()
{
    re ll s=0,op=0;
    re char ch=getchar();
    while(!isdigit(ch))op|=ch=='-',ch=getchar();
    while(isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    return op?-s:s;
}
int main() 
{
    static mt19937_64 gen(random_device{}());
    static uniform_int_distribution<unsigned long long> dis;
    int t;
    t=qread();
    while (t--) 
    {
        int n;
          n=qread();
        if (n == 0)
        {
            printf("1\n");
            continue;
        }
        
        vector<ull> rand_vals(n);
        For(i,0,n-1)rand_vals[i] = dis(gen);
        
        vector<pair<ll, ull> > events;
        events.reserve(2 * n);
        
        for (int i = 0; i < n; i++) 
        {
            ll l, r;
            scanf("%lld %lld", &l, &r);
            
            events.emplace_back(l, rand_vals[i]);
            events.emplace_back(r + 1, rand_vals[i]);
        }
        
        sort(events.begin(), events.end());
        
        ull current = 0;
        unordered_set<ull> seen;
        seen.insert(0);
        int count = 1;
                
        for (int i=0;i<events.size(); ) 
        {
            ll pos=events[i].first;
            int j=i;
            while (j<events.size()&&events[j].first==pos) 
            {
                current^=events[j].second;
                j++;
            }
            if (seen.find(current)==seen.end())
            {
                seen.insert(current);
                count++;
            }
            i=j;
        }
        printf("%d\n", count);
    }
    return 0;
}

View Code


4. 1012核心共振

知识点:坐标变换

复制代码
#include<bits/stdc++.h> 
#define in inline
#define re register
#define ll long long
#define db double
#define ls(a) a<<1
#define rs(a) a<<1|1
#define sz(a) int(a.size())
#define inf 0x3f3f3f3f 
#define me(a,num) memset(a,num,sizeof(a))
#define mc(a,b) memcpy(a,b,sizeof(a))
#define For(i,a,n) for(re int (i)(a);(i)<=(n);(i)=-~(i))
#define Bor(i,n,a) for(re int (i)(n);(i)>=(a);--(i))
#define debug cout<<"QWQ"<<endl
#define Time cout<<(db)clock()/CLOCKS_PER_SEC<<endl
using namespace std;
const ll R=1<<21,N=1e6+10,mod=1e9+7,inv2=500000004;
in ll qread()
{
    re ll s=0,op=0;
    re char ch=getchar();
    while(!isdigit(ch))op|=ch=='-',ch=getchar();
    while(isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    return op?-s:s;
}
in ll solve(vector<ll>uu,vector<ll>a,ll n)
{
    vector<ll>anss(n,0),sum(n,0);
    vector<ll>x=uu;
    sort(x.begin(),x.end());
    sum[0]=x[0];
    For(i,1,n-1)sum[i]=sum[i-1]+x[i];
//    debug;
//    For(i,0,n-1)cout<<x[i]<<" ";
//    cout<<endl;
    ll ans=0,ansl=0,ansr=0;
    For(i,0,n-1)
    {
        ansl=0,ansr=0;
        ll zb=uu[i];
        ll l=lower_bound(x.begin(),x.end(),zb)-x.begin();
        ll r=upper_bound(x.begin(),x.end(),zb)-x.begin();
        if(l>0)ansl=l*zb-sum[l-1];
        if(r<n)ansr=(sum[n-1]-sum[r-1])-(n-r)*zb;
        anss[i]=ansl+ansr;
    }
//    For(i,0,n-1)cout<<anss[i]<<" ";
    For(i,0,n-1)ans=(ans+(a[i]%mod)*(anss[i]%mod))%mod;
    return ans;

}
int main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    ll t=qread();
    while(t--)
    {
        ll n=qread();
        vector<ll>u(n),v(n),a(n);
        For(i,0,n-1)
        {
            ll x,y,val;
            x=qread(),y=qread(),val=qread();
            u[i]=x+y,v[i]=y-x,a[i]=val;
        }
        ll ansu=0,ansv=0;
        ansu=solve(u,a,n);
//        debug;cout<<ansu<<endl;
        ansv=solve(v,a,n);
//        debug;cout<<ansv<<endl;
        ll ans=(ansu+ansv)%mod*inv2%mod;
        printf("%lld\n",ans);
    }
    
    return 0;
} 

View Code


5. 1008 01环

知识点:模拟分析

存在101010和010101两种合法情况,对两种情况分别判断给出序列的不正确位置,对于连续长L的不正确段要至少操作(L+1)/2次

复制代码
#include<bits/stdc++.h> 
#define in inline
#define re register
#define ll long long
#define db double
#define ls(a) a<<1
#define rs(a) a<<1|1
#define sz(a) int(a.size())
#define inf 0x3f3f3f3f 
#define me(a,num) memset(a,num,sizeof(a))
#define mc(a,b) memcpy(a,b,sizeof(a))
#define For(i,a,n) for(re int (i)(a);(i)<=(n);(i)=-~(i))
#define Bor(i,n,a) for(re int (i)(n);(i)>=(a);--(i))
#define debug cout<<"QWQ"<<endl
#define Time cout<<(db)clock()/CLOCKS_PER_SEC<<endl
using namespace std;
const int R=1<<21,N=1e6+10;
in int qread()
{
    re int s=0,op=0;
    re char ch=getchar();
    while(!isdigit(ch))op|=ch=='-',ch=getchar();
    while(isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    return op?-s:s;
}
int n;
char s[N];
bool ch[N];
in int nxt(int u)
{
    return (u==n)?1:u+1;
}
in int lst(int u)
{
    return (u==1)?n:u-1;
}
in int op(int type)
{
    For(i,1,n)
    {
        int u=(i+type)&1;
        int val=(s[i]=='1');
        ch[i]=u^val;
    }
    int num=0;
    For(i,1,n)num+=ch[i];
    if(num==n)return n;
    num=0;
    For(i,1,n)
    {
        if(ch[i]&&!ch[lst(i)])
        {
            int cnt=0;
            for(int j=i;ch[j];j=nxt(j))++cnt;
            num+=(cnt+1)/2;
        }
    }
//    debug;
    return num;
}
int main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    int t;
    t=qread();
    while(t--)
    {
        n=qread();
        scanf("%s",s+1);
        cout<<min(op(0),op(1))<<endl;
    }
    For(i,1,n)
    return 0;
} 

View Code