Codeforces Global Round 11——E随机+线性基待补

A - Avoiding Zero

不难发现如果数组所有元素和为0一定不能满足条件,否则一定能满足。
假设所有元素和不为0尝试以下构造,如果正数和小于负数和的绝对值,那么逆序排列,否则顺序排列,这样一定满足题意。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=60;
int a[N];
int main()
{
    IO;
    int T=1;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        int s=0;int s1=0,s2=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            if(a[i]<0) s1+=a[i];
            else s2+=a[i];
            s+=a[i];
        }
        if(s==0)
        {
            cout<<"NO\n";
            continue;
        }
        sort(a+1,a+1+n);
        if(-s1<s2) reverse(a+1,a+1+n);  
        cout<<"YES\n";
        for(int i=1;i<=n;i++) cout<<a[i]<<' ';
        cout<<'\n';
    }
    return 0;
    
}

B - Chess Cheater

瞎搞的

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100010;
char s[N];
int n,k;
int main()
{
    IO;
    int T=1;
    cin>>T;
    while(T--)
    {
        cin>>n>>k;
        cin>>s+1;
        priority_queue<int,vector<int>,greater<int>> q1,q2,q3;
        priority_queue<int> p1,p2;
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            if(s[i]=='L') cnt++;
            else 
            {
                if(!cnt) continue;
                if(i>cnt+1&&s[i-cnt-1]=='W'&&i<=n&&s[i]=='W') 
                    q1.push(cnt);
                else if(i>cnt+1&&s[i-cnt-1]=='W'||i<=n&&s[i]=='W') 
                    q2.push(cnt);
                else 
                    q3.push(cnt);
                cnt=0;
            }
        }
        if(cnt) 
        {
            if(n>cnt&&s[n-cnt]=='W') q2.push(cnt);
            else q3.push(cnt);
        }
        int res=0;
        while(k&&q1.size())
        {
            auto v=q1.top();q1.pop();
            if(k>=v) res+=2*v+1,k-=v;
            else p1.push(v);
        }
        while(k&&q2.size())
        {
            auto v=q2.top();q2.pop();
            if(k>=v) res+=2*v,k-=v;
            else p2.push(v);
        }
        while(k&&(p1.size()||p2.size()))
        {
            res+=2*k;
            k=0;
        }
        if(k&&q3.size()) 
        {
            auto v=q3.top();
            res=2*min(k,v)-1;
        }
        for(int i=1;i<=n;i++)
        {
            if(s[i]=='W')
            {
                if(i>1&&s[i-1]=='W') res+=2;
                else res++;
            }
        }
        cout<<res<<'\n';
    }
    return 0;
}

C - The Hard Work of Paparazzi

刚开始以为是个图论题,但是有一个条件就是就算你先到了一个点你仍然要等到那个人出现的时间,也就是每个点的时间是确定的,因此每个点的时间是确定的考虑dp
状态表示: f i f_i fi表示目前在第 i i i个点时答案的最大值
状态转移: f i = m a x ( f i , f i + 1 ) ( ∣ x i − x j ∣ + ∣ y i − y j ∣ ≤ t i − t j ) f_i=max(f_i,f_i+1)(|x_i-x_j|+|y_i-y_j|\leq t_i-t_j) fi=max(fi,fi+1)(xixj+yiyjtitj)

这样转移会发现复杂度爆炸 O ( n 2 ) O(n^2) O(n2),我们可以发现还有个东西一直没有用也就是地图的尺寸 r r r,由于 t i t_i ti是顺序给出的如果当前的 t i − t j ≥ 2 r t_i-t_j\ge 2r titj2r不难发现 1 − j 1-j 1j f 1 − j f_{1-j} f1j都能更新 f i f_i fi由此尝试维护前缀进行优化。
时间复杂度好像是 O ( n r ) O(nr) O(nr)

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=100010;
int r,n;
int f[N];
struct node
{
    int x,y,t;
}a[N];
int mx[N];
int main()
{
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
        cin>>r>>n;
        for(int i=1;i<=n;i++) cin>>a[i].t>>a[i].x>>a[i].y;
        memset(f,-0x3f,sizeof f);
        memset(mx,-0x3f,sizeof mx);
        a[0]={1,1,0};
        f[0]=mx[0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=i-1;j>=0;j--)
            {
                if(a[i].t-a[j].t>=2*r) 
                {
                    f[i]=max(f[i],mx[j]+1);
                    break;
                }
                if(abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y)<=a[i].t-a[j].t) 
                    f[i]=max(f[i],f[j]+1);
            }
            mx[i]=max(mx[i-1],f[i]);
        }
        int res=0;
        for(int i=1;i<=n;i++) res=max(res,f[i]);
        cout<<res<<'\n';
    }
    return 0;
}

剩下的题待补

D - Unshuffling a Deck

今天早上起来想了一下这个题,想了个贪心的做法然后上课前交代码发现贪心思路不行,然后吃完午饭又想了个做法水过去了

尝试每次使得一个数排列归位。这里尝试按照 n − 1   n − 2 …   1 n-1\ n-2\dots \ 1% n1 n2 1的顺序
首先我们让排好序的排成(目前已经有cnt个数“归位”)这样子 { [ n , n − 1 , n − 2 , . . . , n − c n t + 1 ] [ . . . n − c n t ] [ . . . . ] } \{[n,n-1,n-2,...,n-cnt+1][...n-cnt][....]\} {[n,n1,n2,...,ncnt+1][...ncnt][....]}我们只需要这样划分就可以在此归位一个数
{ [ 1 ] . . . [ 1 ] [ 1 ] ⏟ c n t [ l e n 1 ] [ l e n 2 ] } \{ \underbrace{[1]...[1][1]}_{cnt}[len_1][len_2]\} {cnt [1]...[1][1][len1][len2]}
这样操作后原序列即变成 { [ . . . . . . ] [ n − c n t , n − c n t + 1 , . . . , n ] } \{[......][n-cnt,n-cnt+1,...,n]\} {[......][ncnt,ncnt+1,...,n]}
然后如法炮制的操作,一共进行n次即可归位。还有些细节可以看代码

细节1:n奇偶性,最后一次操不能让序列变成全部逆序的情况,需要顺序
细节2:划分需要至少划分2个断,最后需要把划分成1个段(无效操作)清除掉。

上述方法一定能在n次操作以内完成序列顺序。


#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=60;
int n,cnt;
int a[N],b[N];
vector<int> ans[N];
int main()
{
    IO;
    int T=1;
    //cin>>T;
    while(T--)
    {
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        bool flag;
        int now=n;
        if(n&1) flag=0;
        else flag=1;
        for(int k=1;k<=n;k++)
        {
            int p;
            for(int i=1;i<=n;i++) 
                if(a[i]==now) p=i;
            //cout<<p<<':';
            //cout<<(int)flag<<'\n';
            if(!flag)// 左边整齐
            {
                for(int i=1;i<=cnt;i++) ans[k].push_back(1);
                if(p-cnt) ans[k].push_back(p-cnt);
                if(n-p) ans[k].push_back(n-p);
                
                for(int i=p+1,j=1;i<=n;i++,j++) b[j]=a[i];// p+1~n -> 1~n-p    n-p
                for(int i=cnt+1,j=n-p+1;i<=p;i++,j++) b[j]=a[i];// cnt+1~p -> n-p+1   p-cnt
                for(int i=1,j=n;i<=cnt;i++,j--) b[j]=a[i];// 1~cnt -> n~n-cnt+1  cnt
                
                
                for(int i=1;i<=n;i++) a[i]=b[i];
            }
            else
            {
                if(p-1>0) ans[k].push_back(p-1);
                if(n-cnt-p+1>0) ans[k].push_back(n-cnt-p+1);
                for(int i=1;i<=cnt;i++) ans[k].push_back(1);
                
                for(int i=1,j=n-p+2;i<=p-1;i++,j++) b[j]=a[i];
                for(int i=p,j=cnt+1;i<=n-cnt;i++,j++) b[j]=a[i];
                for(int i=n-cnt+1,j=cnt;i<=n;i++,j--) b[j]=a[i];
                for(int i=1;i<=n;i++) a[i]=b[i];
                
            }
            now--;
            cnt++;
            flag^=1;
        }
        int res=0;
        for(int i=1;i<=n;i++)
            if(ans[i].size()>1) res++;
        cout<<res<<'\n';
        for(int i=1;i<=n;i++)
        {
            if(ans[i].size()>1)
            {
                cout<<ans[i].size()<<' ';
                for(auto t:ans[i]) cout<<t<<' ';
                cout<<'\n';
            }
        }
    }
    return 0;
}

E - Xum

要加哟哦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值