SMU2025寒假训练周报3

一.2025牛客寒假算法基础集训营6

1.好伙计猜拳

原题链接:B-好伙计猜拳_2025牛客寒假算法基础集训营6

有点类似最长上升子序列,但是多了个交换操作,只需要用二维数组来表示一下状态就好,转移时假设当前位置为 i,枚举上一个位置 j,如果能把 (或bi,ai)接到 (或bj,aj)后面,则可以花费(i−j−1)*c1来删除两者中间的那段。

查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[1000000],b[1000000];

signed main()
{
    //ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n,c1,c2;
        cin>>n>>c1>>c2;
        for(int i=1;i<=n;i++)cin>>a[i]>>b[i];
        vector<vector<int>>dp(n+10,vector<int>(2,1e18));
        dp[0][0]=0;
        dp[0][1]=0;
        a[n+1]=LLONG_MAX,b[n+1]=LLONG_MAX;
        for(int i=1;i<=n+1;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(a[i]>=a[j]&&b[i]>=b[j])
                {
                    dp[i][0]=min(dp[i][0],dp[j][0]+(i-j-1)*c1);
                    dp[i][1]=min(dp[i][1],dp[j][1]+(i-j-1)*c1+c2);
                }
                if(a[i]>=b[j]&&b[i]>=a[j])
                {
                    dp[i][0]=min(dp[i][0],dp[j][1]+(i-j-1)*c1);
                    dp[i][1]=min(dp[i][1],dp[j][0]+(i-j-1)*c1+c2);
                }
            }
        }
        cout<<min(dp[n+1][0],dp[n+1][1])<<endl;
    }
    return 0;
}

2.小鸡的排列构造

原题链接:H-小鸡的排列构造_2025牛客寒假算法基础集训营6

打表可以观察出规律,r-l是奇数时倒序就没问题,但是是偶数时我们可以两个两个的排,将i-1排在i前面就能满足所有情况

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        int ans=0;
        for(int i=1;i<=m;i++)
        {
            int a,b,c;
            cin>>a>>b>>c;
            ans=b-a;
        }
        if(ans%2==0)
        {
            for(int i=n;i>=1;i-=2)
            {
                if(i!=1)
                    cout<<i-1<<" "<<i<<" ";
                else cout<<1;
            }
        }
        else
            for(int i=n;i>=1;i--)
                cout<<i<<" ";
        cout<<endl;
    }
    return 0;
}

3.小鸡的排列构造的checker

原题链接:I-小鸡的排列构造的checker_2025牛客寒假算法基础集训营6

主席树板子,找出区间中比目标位置数字大的数的个数,再用边界计算位置即可,注意控制空间

查看代码
 #include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=3e5+10;
struct node{
    int l;
    int r;
    int sum;
}p[maxx*10];
int a[maxx],b[maxx],root[maxx];
int n,m,tot;
/*--------------主席树--------------*/
int build(int l,int r)
{
    int cur=++tot;
    p[cur].sum=0;
    if(l==r) return cur;
    int mid=l+r>>1;
    p[cur].l=build(l,mid);
    p[cur].r=build(mid+1,r);
    return cur;
}
int update(int rot,int pos,int l,int r)
{
    int cur=++tot;
    p[cur]=p[rot];
    p[cur].sum++;
    if(l==r) return cur;
    int mid=l+r>>1;
    if(pos<=mid) p[cur].l=update(p[rot].l,pos,l,mid);
    else p[cur].r=update(p[rot].r,pos,mid+1,r);
    return cur;
}
int query(int lrot,int rrot,int l,int r,int pos)
{
    if(l==r) return p[rrot].sum-p[lrot].sum;
    int mid=l+r>>1;
    int sum=0;
    if(pos<=mid) sum=query(p[lrot].l,p[rrot].l,l,mid,pos)+p[p[rrot].r].sum-p[p[lrot].r].sum;
    else sum=query(p[lrot].r,p[rrot].r,mid+1,r,pos);
    return sum;
}
int main()
{
    int l,r,x;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        tot=0;
        scanf("%d%d",&n,&m);
        tot=0;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+1+n);
        int len=unique(b+1,b+1+n)-b-1;//离散化
        root[0]=build(1,len);
        for(int i=1;i<=n;i++) root[i]=update(root[i-1],lower_bound(b+1,b+1+len,a[i])-b,1,n);
        while(m--)
        {
            scanf("%d%d%d",&l,&r,&x);
            int zz=query(root[l-1],root[r],1,n,lower_bound(b+1,b+1+len,a[x])-b);
            printf("%d\n",r-zz+1);
        }
    }
    return 0;
}

二.个人训练赛4

1.C. Li Hua and Chess

原题链接:Problem - C - Codeforces

交互题

选定(1,1),这样目标点的范围就缩小到如下位置:

然后对(1,k+1),(k+1,1)提问,可以进一步缩小答案范围 ,对(1,k+1)询问,如果离(1,1)的距离大于(1,k+1)的距离,那么就在右边界,否则就在下边界

查看代码
int query(int x,int y){
	if(x>n||y>m) return Inf;
	int ans;
	cout<<"?"<<" "<<x<<" "<<y<<'\n';
	cin>>ans;
	return ans;
}
void output(int x,int y){
	cout<<"!"<<" "<<x<<" "<<y<<'\n'; 
}
void solve(){
	cin>>n>>m;
	int x=query(1,1);
	int y=query(1,x+1);
	int z=query(x+1,1);
	if(y<x) output(y+1,x+1);
	else output(x+1,z+1);
}

三.个人练习赛5

1.C. Sequence Master

原题链接:Problem - C - Codeforces

打表找规律,全0是通用解。当n=1时,答案是a1-a2的绝对值;n=2时,有两种其他合法的(2,2,2,2)和(2,-1,-1,-1);n为大于等于3的奇数时,只能全0;n为大于2的偶数时,还存在(n,-1,-1....,-1)

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
int a[1000000];
signed main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        int ans=0;
        for(int i=1;i<=2*n;i++)cin>>a[i],ans+=abs(a[i]);
        if(n==1)
        {
            cout<<abs(a[1]-a[2])<<endl;
            continue;
        }
        if(n==2)
        {
            int sum=0;
            for(int i=1;i<=4;i++)
            {
                sum+=abs(a[i]-2);
            }
            ans=min(ans,sum);
            int tmp=0;
            for(int i=1;i<=4;i++)
            {
                tmp=abs(a[i]-2);
                for(int j=1;j<=4;j++)
                {
                    if(i==j)continue;
                    tmp+=abs(a[j]+1);
                }
                ans=min(ans,tmp);
            }
            cout<<ans<<endl;
            continue;
        }
        if(n&1)cout<<ans<<endl;
        else
        {
            int sum=0;
            for(int i=1;i<=2*n;i++)sum+=abs(a[i]+1);
            for(int i=1;i<=2*n;i++)
            {
                ans=min(ans,sum-abs(a[i]+1)+abs(a[i]-n));
            }
            cout<<ans<<endl;
        }
    }
    return 0;
}

 

posted @ 2025-02-16 16:20  伊芙加登  阅读(10)  评论(0)    收藏  举报