Educational Codeforces Round 159 (Rated for Div. 2)(B 二分贪心 Cgcd D二分+前缀和 E字典树)

A - Binary Imbalance

有只要在01之间插入就能制造无限个0,没有0就统计0 1个数即可

#include
using namespace std;
const int N =1100+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair PII;
const long long inf=1e17;
using node=tuple;
int n,m,k;
int s[N][N];
char p[N][N];
void solve()
{cin>>n;
    string s;cin>>s;
    int cnt0=0;
    bool ok=false;
    for(int i=0;i0){
        cout<<"Yes\n";
    }
    else cout<<"No\n";
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
}

B - Getting Points

具有单调性,n也挺大,我直接二分可以休息多少天了

然后直接算n天一共有多少个任务,然后有个特殊情况是

如果我最后一天刚好是发布任务的那天且今天是周一

那么我当前的任务只能让最后一个做

前面能做的任务要减1,能解决的总任务是2*x-1

#include
using namespace std;
const int N =2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair PII;
const long long inf=1e17;
using node=tuple;
int n,m,k;
void solve()
{
    int p,l,t;
    cin>>n>>p>>l>>t;
    auto check=[&](int x)
    {
        x=n-x;
        int now=(n+6)/7;
        int res=l*x+min(now,x*2)*t;
        if(n%7==1){
            res=l*x+min(now-1,x*2-1)*t+t;
        }
        return res>=p;
    };
    int ll=0,r=n;
    while(ll>1;
        if(check(mid)) ll=mid;
        else r=mid-1;
    }
    cout<>t;
    while(t--) solve();
}

C:

我直接一眼直觉得出结论了ahhh(虽然不知道这想法哪来的,反正就很直觉)

赛后证明一下

每个数要变成一个统一的数字 x

那么第一个数要是 a+kw=x ->> x-a=kw

第二个数是 b+kw=x -> x-b=kw

....

因为只能数只能增大不能减少,所以我们直接让x为最大值即可

然后求最大值和每个数的差值的最大公因数即可

然后增加一个数,肯定也要上最大值加上这个gcd了

然后我是直接枚举两种情况的

比最大值大,和比最大值小的

循环n+1次肯定都能找到,然后计算代价即可

#include
using namespace std;
const int N =2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair PII;
const long long inf=1e17;

int n,m,k;
int a[N];
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    if(n==1){
        cout<<1<<"\n";return ;
    }
    sort(a+1,a+1+n);
    vector b;
    for(int i=1;i mp;
    for(int i=1;i<=n;i++){
        mp[a[i]]++;
    }
    int mn=2e18;
    int cnt=n;
    for(int i=0,now=a[n];i<=n;i++){
        now+=g;
        if(!mp.count(now)){
            mn=min(mn,n*(now-a[n])/g);
            break;
        }
    }
    for(int i=0,now=a[n];i<=n;i++){
        now-=g;
        if(!mp.count(now)){
            mn=min(mn,abs(now-a[n])/g);
            break;
        }
    }
    cout<>t;
    while(t--) solve();
}

D - Robot Queries

手画一下可以发现,中间那段翻转不影响最终结果

然后还是做不了发现

然后我们要进行转化一下

转化成前缀和,把区间问题变成选择两个点后到达的点是xi,yi

对于不是反转的区间 [1,L-1]和[R-1,N]这两个区间,直接从里面找即可

对于反转的我们其实也可以直接找

比如要找的点是 xi,y1

那么还原回来

pre[L-1]+pre[R]-pre[x-1]=xi

pre[x-1]=pre[L-1]+pre[R]-xi

注意这里的pre[R]-pre[x-1]是代表着翻转的区间的变化量

#include
using namespace std;
const int N =2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair PII;
const long long inf=1e17;
using node=tuple;
int n,m,k;
int a[N];
const int dx[4]={1,-1,0,0};
const int dy[4]={0,0,1,-1};
mapdir={{'U',2},{'D',3},{'L',1},{'R',0}};
void solve()
{
    cin>>n>>m;
    string s;
    cin>>s;
    vector pre(n+10);
    pre[0]={0,0};
    s="?"+s;
    for(int i=1;i<=n;i++){
        int k=dir[s[i]];
        auto [x,y]=pre[i-1];
        x+=dx[k],y+=dy[k];
        pre[i]={x,y};
    }
    vector> v(6*n+10);
    for(int i=0;i<=n;i++){
        auto [x,y]=pre[i];
        v[x+3*n].insert({y,i});
    }
    for(int i=0;i<=4*n;i++){
        v[i].insert({inf,inf});
    }
    while(m--){
        int tx,ty,L,R;
        cin>>tx>>ty>>L>>R;
        int px,py;

        px=tx,py=ty;
        auto [y1,id1]=*v[px+3*n].lower_bound({py,0});
        if(y1==py&&id1<=L-1){
            cout<<"YES\n";
            continue;
        }

        //[L,R]
        auto [adx,ady]=pre[L-1];
        auto [bdx,bdy]=pre[R];
        px=bdx+adx-tx,py=bdy+ady-ty;
        //cout<=L-1&&id2<=R){
            cout<<"YES\n";
            continue;
        }

        //[R+1,n]
        px=tx,py=ty;
        auto [y3,id3]=*v[px+3*n].lower_bound({py,R+1});
        if(y3==py&&id3>=R+1&&id3<=n){
            cout<<"YES\n";
            continue;
        }
        cout<<"NO\n";
    }
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
   // cin>>t;
    while(t--) solve();
}

E - Collapsing Strings

这个题之前我博客遇到过相似的题

然后也直接一眼题...

直接跑个字典树,然后翻转字符串减去要减去的贡献即可

我的query里面你可以

Educational Codeforces Round 159 (Rated for Div. 2)(B 二分贪心 Cgcd D二分+前缀和 E字典树)_第1张图片

第一个点是p,第二个点的cnt[p]是3

然后要减去的代价是两个点之间消失的个数*当前点的长度-1

3-2就代表着我从第二个点到第三个点少了一个可以匹配的字符串

说明这一个字符串只能匹配到长度2的前缀他就没了

然后还有个问题是如果匹配完了我的lst不为0

说明有lst个字符串能完整匹配完

#include
using namespace std;
const int N =1e6+10,mod=998244353;

typedef long long LL;
typedef pair PII;
const long long inf=1e17;
using node=tuple;
int n,m,k;
int a[N];
int tr[N][27];
string s[N];
int cnt[N],idx;
long long res;
void insert(string s){
    int p=0;
    for(int i=0;i>n;
 
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        insert(s[i]);
        sum+=s[i].size();
    }

    for(int i=1;i<=n;i++){
        res+=sum+1ll*(int)(s[i].size())*n;
        reverse(s[i].begin(),s[i].end());
        query(s[i]);
    }
    cout<>t;
    while(t--) solve();
}

你可能感兴趣的:(算法,数据结构,codeforce)