Codeforces Round #501 (Div. 3) 训练总结及题解

A题因为交了错了文件和试样例慢了2mins用了5mins,B题读题较慢用了13mins,C题读题也偏慢用了7mins,D题少考虑一种情况wa了3发用时22mins,E题读错了判断条件,写完用了40mins。F题场后看题解学会。
总结:

  1. 每次文件要在场前调整好。
  2. 过了A题仍要快速读题。
  3. D题的多种情况,wa了一发之后要多考虑。
  4. E题太浮躁了,不愿意重读题,靠样例猜题意。

题解:
A.
题意:给你n个区间,m代表总区间1-m,现判断给的n区间与总区间未交集的范围的总数。
思路:暴力即可,数据范围大可以用线段树,或者预处理。
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e3+5;
bool vis[maxn];

int main(){
    IO;
    int n,m;cin>>n>>m;
    forn(i,n){
        int l,r;cin>>l>>r;
        for(int i = l;i<=r;i++) vis[i] = 1;
    }
    vector<int>ans;
    for1(i,m) if(!vis[i]) ans.push_back(i);
    cout << ans.size()<<'
';
    for(auto x:ans) cout << x<< ' ';







    return 0;
}

B
题意:给字符串s和t,长度50,问是否可以移动最多1e4次,每次仅可移动相邻位置,使得t==s。
思路:暴力移动(On^2)
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int num[26],num2[26];
int main(){
    IO;
    int n;cin>>n;
    string s,t;cin>>s>>t;
    forn(i,n){
        num[s[i]-'a']++;
        num2[t[i]-'a']++;
    }
    vector<int>ans;
    forn(i,26)if(num[i]!=num2[i])return cout<<-1<<'
',0;
    forn(i,n){
        if(s[i]!=t[i]){
            int pos = i;
            for(int j = i;j<n;j++){
                if(s[j]==t[i]){
                    pos = j;break;
                }
            }
            for(int j = pos-1;j>=i;j--){
                swap(s[j+1],s[j]);
                ans.push_back(j+1);
            }
        }
    }

    cout << ans.size()<<'
';

    for(auto x:ans) cout <<x<<' ';





    return 0;
}

C.
题意:给n个物品1e5,一个限制k1e9。每个物品有一个初始值和变动值。问最少改动多少初始值使得所有物品sum<=k。
思路:排序
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

int main(){
    IO;
    int n,m;cin>>n>>m;
    vector<int>a(n);ll sum = 0;
    forn(i,n){
        int x,y;cin>>x>>y;
        a[i] = x-y;
        sum+=x;
    }
    sort(a.begin(),a.end());
    if(sum<=m) return cout << 0<<'
',0;
    forn(i,n){
        sum-=a.back();a.pop_back();
        if(sum<=m) return cout << i+1<<'
',0;
    }
    cout << -1 <<'
';





    return 0;
}

D
题意:一个区间1,n1e9。初始在1点,问是否可以移动m2e5次使得移动总距离达到k1e18。不可以输出-1,可以构造出来每次移动至何点。
思路:数学,有坑点:1.longlong 2.移动可能不达k次
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(ll i=0;i<n;i++)
#define for1(i,n) for(ll i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;

int main(){
    IO;
    ll n,m,s;cin>>n>>m>>s;
    //n= 1e9,m= 2e5,s=1e18;
    //cerr<<(n-1)*m<<'
';
    if(1ll*(n-1)*m<s) return cout<<"NO"<<'
',0;
    if(m>s) return cout<<"NO"<<'
',0;
    cout <<"YES"<<'
';
    ll v = s/m,x = s%m;
    vector<ll>ans(m);
    ll pos = 1;
    forn(i,m){
        if(i&1){
            pos-=v;
            if(x>0)pos--;
        }
        else{
            pos+=v;
            if(x>0)pos++;
        }
        x--;
        ans[i] = pos;
    }
    for(auto x:ans) cout <<x<<' ';


    return 0;
}

E
题意:让你在图中找到x个由’'组成的十字架,x<nm,问十字架能否覆盖所有*,可以的话输出每个十字架的中心位置和他的长度。
思路:出题人低估了cf的评测姬ON^3也可过。
On^2是用dp先预处理四个数组及每个点向上下左右最远的‘.’距离。然后取四数组min,再dp或者其他方法把覆盖点去掉,最后输出。
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

char a[1005][1005];
int d[1005][1005],u[1005][1005],l[1005][1005],r[1005][1005];
int pos[1005][1005],pos2[1005][1005];
vector<pair<pair<int,int>,int> >ans;

int main(){
    //IO;
    int n,m;cin>>n>>m;
    for1(i,n) for1(j,m) cin>>a[i][j];
    for1(i,n){
        for1(j,m){
            if(a[i-1][j]=='*') u[i][j] = u[i-1][j]+1;
            if(a[i][j-1]=='*') l[i][j] = l[i][j-1]+1;
        }
    }
    for(int i = n;i>=1;i--){
        for(int j = m;j>=1;j--){
            if(a[i+1][j]=='*') d[i][j] = d[i+1][j]+1;
            if(a[i][j+1]=='*') r[i][j] = r[i][j+1]+1;
        }
    }
    for1(i,n)for1(j,m)if(a[i][j]=='*'){
        int len = min({u[i][j],r[i][j],l[i][j],d[i][j]});
        if(len){
            ans.push_back({{i,j},len});
            pos[i][j-len]--;
            pos[i][j+len+1]++;
            pos2[i-len][j]--;
            pos2[i+len+1][j]++;
        }
    }
    for1(i,n){
        int cnt = 0;
        for1(j,m){
            cnt+=pos[i][j];
            if(cnt!=0) a[i][j] = '.'; 
        }
    }
    for1(j,m){
        int cnt = 0;
        for1(i,n){
            cnt+=pos2[i][j];
            if(cnt!=0) a[i][j] = '.';
        }
    }
    /* err<<'
';
    for1(i,n){
        for1(j,m)cerr<<a[i][j];
        cerr<<'
';
    }*/
    for1(i,n)for1(j,m)if(a[i][j]=='*')return cout <<-1<<'
',0;
    cout << ans.size()<<'
';
    for(auto x:ans){
        cout <<x.first.first<<' '<<x.first.second<<' '<<x.second<<'
';
    }

    return 0;
}

F
题意:给你一个括号序列S,再给你一个N,求长度为2N,且含有子串S,满足括号匹配的序列总数。
思路:第一次做字符串dp,跟ac自动机的题有点像。思路随意构造,看能否构造包含s的长度为2*n的母串。
dpijk,i表示构造到第几位,j表示’(‘的个数 -’)’的个数,k表示构造当前情况和子串相同到了第k位。
状态转移考虑两种情况
sk==’(‘和sk==’)‘及所枚举的这种情况到达s串的第k位等于’(‘或等于’)’
那么构造时候分两种往末尾添加相同的字符和不相同的字符,不相同的时候类似kmp和ac自动机找到失配的位置。
代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(ll i=0;i<n;i++)
#define for1(i,n) for(ll i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
ll dp[205][105][205],nex[205],fail1[205],fail2[205],fail[205];
const ll mod = 1e9+7;
void getnex(string s){
    ll len = s.size(),i = 0,j = -1;
    nex[0] = -1;
    while(i<len){
        if(s[i]==s[j]||j==-1) nex[++i] = ++j;
        else j = nex[j];
    }
    for1(i,len-1)if(nex[i]){
        ll x = nex[i];
        while(s[x]!='('){
            x = nex[x];
            if(!x)break;
        }
        fail1[i] = x; 
        x = nex[i];
        while(s[x]!=')'){
            x = nex[x];
            if(!x)break;
        }
        fail2[i] = x;
    }
}
void build_fail(string s) {
    ll slen = s.size();
    ll j=0;
    for(ll i=1;i<slen-1;i++) {
        while(j&&s[j]!=s[i]) j=fail[j];
        if(s[i]==s[j]) j++;
        fail[i+1]=j;
    }
    //forn(i,slen+1) cerr<<fail[i]<<' ';
   // cerr<<'
';

    for(ll i=slen-1;i;i--) {
        ll j=i;
        while(j&&s[i]==s[j]) j=fail[j];
        if(s[i]!=s[j]) j++;
        fail[i]=j;
    }//forn(i,slen+1) cerr<<fail[i]<<' ';
   // cerr<<'
';
}

int main(){
    IO;
    ll n;string s;cin>>n>>s;
    ll len = s.size();
    //getnex(s);
    build_fail(s);
    dp[0][0][0] = 1;
    forn(i,n<<1){
        forn(j,n+1){
            forn(k,len){
                if(s[k]=='('){
                    (dp[i+1][j+1][k+1] += dp[i][j][k])%=mod;
                    if(j) (dp[i+1][j-1][fail[k]] += dp[i][j][k])%=mod;
                }else{
                    (dp[i+1][j+1][fail[k]] += dp[i][j][k])%=mod;
                    if(j) (dp[i+1][j-1][k+1] += dp[i][j][k])%=mod;
                }
            }
            (dp[i+1][j+1][len] += dp[i][j][len])%=mod;
            if(j)  (dp[i+1][j-1][len] += dp[i][j][len])%=mod;
        }
    }
    /* forn(i,n<<1+1){
        forn(j,n+1){
            forn(k,len+1){
                cerr<<dp[i][j][k]<<' ';
            }
            cerr<<'
';
        }
        cerr<<"!@#"<<'
';
    }*/
    cout <<dp[n<<1][0][len]<<'
';
    /*5
()))() */
    return 0;
}
人一我百,人十我万。
原文地址:https://www.cnblogs.com/AlexPanda/p/12520322.html