Educational Codeforces Round 154 (Rated for Div. 2)

A:
直接找出两位数的质数就行,

#include
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
using node=tuple;
typedef pair PII;
int n,m;

bool check(int n){
    if(n<=3) return n>1;
    if(n%6!=1&&n%6!=5) return false;
    for(int i=5;i<=n/i;i+=6){
        if(n%i==0||n%(i+2)==0) return false;
    }
    return true;
}
void solve(){
    string s;
    cin>>s;
    for(int i=0;i>t;
    while(t--) solve();
}

B:

额懒得思考我直接dp了

预处理哪些区间是能通过操作变成一样的

然后dp:前i个数能不能变成相同数

#include
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
using node=tuple;
typedef pair PII;
int n,m;


void solve(){
    string a,b;
    cin>>a>>b;
    n=a.size();
    a="?"+a;
    b="?"+b;
    vector> st(n+10,vector(n+10,0));
    vector f(n+10,0);
    f[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++){
            if(a[i]==a[j]&&b[i]==b[j]&&b[i]==a[i]){
                st[i][j]=1;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++){
            if(st[j][i]){
                f[i]|=f[j];
                f[i]|=f[j-1];
            } 
        }
    }
   
    if(f[n]) cout<<"YES\n";
    else cout<<"NO\n";
}

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

C:

对于1确定了什么,确定了当前数的cnt1-cnt0个数即cur当前全是递增
对于0确定了什么,确定了最后一个数一定是降序的数 cur 
删除的时候因为要从后往前删:
可能删递增的数,也可能删递减的数(前提最后一个数要大于cur)
增加的时候,可能增加递增,可能增加递减

r记录当前前面确定了多少个数最短的递增前缀

#include
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
using node=tuple;
typedef pair PII;
int n,m;


void solve(){
   string s;cin>>s;
   n=s.size();
   s="?"+s;
   vector st;
   int cur=0,r=0;
   for(int i=1;i<=n;i++)
   {
       if(s[i]=='+')//一个数的时候只能是递增
       {
           if(++cur==1) 
           r=cur;
       }
       else if(s[i]=='-')//
       {
           r=min(r,--cur);//可能减去递增的数
           if(st.size()&&st.back()>cur){//也可能减去递减的数
               st.pop_back();
           }
       }
       else if(s[i]=='1')
       {
           if(st.size()){
               cout<<"NO\n";
               return;
           }
           r=cur;
       }
       else{
           if(cur==r)//当前数前面全是递增
           {
               cout<<"NO\n";
               return ;
           }
           if(st.empty()||s[i]!=s[i-1])//最后一个数一定是降序加入
           st.push_back(cur);
       }
   }
   cout<<"YES\n";
   
}

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


D:前后缀分解

首先乘上负数能让一段连续递减的区间变成连续递增的区间

然后预处理出连续递增和递减的前缀和后缀

1 1 2 2 2

假设处理连续递增区间

通过样例可得1遇到第二个1有两个做法:

把下标2到4同时乘上一个数,不改变2到4的之间每个数的大小关系

单独把下标2乘上一个数使得比前面一个数大

那么下标3的数有两种情况:

如果a[3]>a[2]:但是a[2]乘上一个数使得a[2]>a[3],肯定也要改变a[3]了

如果a[3]<=a[2]:a[2]乘上一个数依然不会改变关系

所以最优肯定是直接改变当前下标到后续区间最优

所以计算只需要关心当前数和下一个数的大小关系即可,统计有多少个数要改变即可

#include
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
using node=tuple;
typedef pair PII;
int n,m;
int a[N];
void solve(){
   cin>>n;
   for(int i=1;i<=n;i++) cin>>a[i];
   vector l(n+10),r(n+10);
   int now=0;
   a[n+1]=a[0]=INT_MAX;

   
   for(int i=2;i<=n;i++)
   {
        l[i]=l[i-1]+(a[i]>=a[i-1]);
        //前缀多少个不是严格递减
   }
   now=0;
   for(int i=n-1;i>=1;i--)
   {
        r[i]=r[i+1]+(a[i]>=a[i+1]);
        //后缀多少个不是严格递增
   }
   int res=min({n,r[1]});
   for(int i=1;i<=n;i++)
   {
       res=min(res,l[i]+1+r[i+1]);
   }
   cout<>t;
    while(t--) solve();
}

你可能感兴趣的:(算法)