2019, XII Samara Regional Intercollegiate Programming Contest

A。双指针如果定义好 l 和 r 的含义就变得很好写了。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn= 500000 + 100;
LL color[maxn],cnt[maxn],a[maxn],ans[maxn];
int main()
{
    LL n;
    scanf("%I64d",&n);
    for( LL i = 1;i <= n;i++ ){
        scanf("%I64d",&a[i]);
    }
    LL l = 0,r = 1;
    while( l < n ){
        while( r <= n && !( a[r] > 0 && cnt[ a[r] ] > 0)  ){
            r++;
            if( a[r-1] < 0 )
            cnt[ -a[r-1] ]++;
        }
        ans[l] = r-l-1;
        l++;
        if( a[l] < 0 ){
            cnt[ -a[l] ]--;
        }
    }
    for( LL i = 0;i < n;i++ )
    printf("%I64d ",ans[i]);
    return 0;
}

B。签到

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn= 1000 + 10;
LL cnt[5];
char str1[maxn],str2[maxn];
int main()
{
    scanf("%s",str1);
    scanf("%s",str2);
    LL n = strlen( str1 );
    for( LL i = 0;i < n;i++ ){
        if( str1[i] == '#' ){
            if( str2[i] == '#' ){
                cnt[3]++;
            }else{
                cnt[2]++;
            }
        }else{
            if( str2[i] == '#' ){
                cnt[1]++;
            }else{
                cnt[0]++;
            }
        }
    }
    bool flag3 = cnt[3] == 0;
    bool flag2 = cnt[2] == 0;
    bool flag1 = cnt[1] == 0;
    if( flag3 ){
        if( !(flag2||flag1) ){
            printf("NO\n");
            return 0;
        }
    }
    LL i = 0;
    for( ;i < cnt[1];i++ ){
        str1[i] = '.';
        str2[i] = '#';
    }
    for( ;i < cnt[1] + cnt[3];i++ ){
        str1[i] = '#';
        str2[i] = '#';
    }
    for( ;i < cnt[1] + cnt[3] + cnt[2];i++ ){
        str1[i] = '#';
        str2[i] = '.';
    }
    for( ;i < n;i++ ){
        str1[i] = '.';
        str2[i] = '.';
    }
    str1[n] = '\0';
    str2[n] = '\0';
    printf("YES\n");
    printf("%s\n",str1);
    printf("%s\n",str2);
    return 0;
}

c。这题打个表发现走不了几步就没有能够新到达的点了。于是瞎写了一发居然过了。(感觉的重要性)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL maxn = 10000000 + 10;
LL vis[maxn];
int main()
{
    //freopen( "456.txt","w",stdout );
    LL p,n;
    scanf("%I64d%I64d",&p,&n);
    vis[0] = 1;
    LL cnt = 1;
    LL h = min( p*2,n );
    for( LL i = 1;i <= h;i++ ){
        LL b = (i*(i+1)/2) % p;
        if( !vis[ b ] ){
            vis[b] = 1;
            cnt++;
        }
    }
    printf("%I64d\n",cnt);
    return 0;
}

D。这题我一开使想找一个点,使其子树中包含所有红点(蓝点),而不包含任何蓝点(红点)。即dfs一遍整个树统计。

但是由于查询次数太多,复杂度爆炸了。所以就得上lca了,找到所有蓝点的lca,和所有红点的lca。若其中一个lca的子树不包含另一个颜色的任何点。就有可行解。(这题启发我找多个点的lca的方法和在树上判断一个点是否是另一个点祖先的方法)

#include<bits/stdc++.h>
using namespace std;
typedef int lint;
typedef long long LL;
const lint maxn = 200000 + 10;
const lint maxm = 500000;
lint ver[maxm],ne[maxm],he[maxn],tot;
vector<lint> vex,vey;
void init(){
    memset( he,0,sizeof( he ) );
    tot = 1;
}
void add( lint x,lint y ){
    ver[++tot] = y;
    ne[tot] = he[x];
    he[x] = tot;
}
struct lca{
    lint de[maxn],anc[maxn][21];
    queue<lint> que;
    void init(){
        memset( anc,-1,sizeof( anc ) );
        while( que.size() ) que.pop();
    }
    void bfs( ){
        que.push( 1 );
        de[1] = 0;
        while( que.size() ){
            lint x = que.front();
            que.pop();
            for( lint cure = he[x];cure;cure = ne[cure] ){
                lint y = ver[cure];
                if( y == anc[x][0] ) continue;
                que.push(y);
                de[y] = de[x] + 1;
                anc[y][0] = x;
                for( lint i = 1; (1 << i) <= de[y]; i++ ){
                    anc[y][i] = anc[ anc[y][i-1] ][i-1];
            }
        }
        }
    }
    lint solve( lint x,lint y ){
       if( x == y ) return x;
        if( de[x] < de[y] ) swap( x,y );
        for( lint i = 18; i >= 0;i-- ){
            lint an = anc[x][i];
            if( an == -1 ) continue;
            if( de[an] >= de[y] ){
                x = an;
            }
        }
        if( x == y ) return y;
        for( lint i = 18; i >= 0; i-- ){
            if( anc[x][i] == -1 || anc[y][i] ==-1 ) continue;
            if( anc[x][i] != anc[y][i] ){
                x = anc[x][i];
                y = anc[y][i];
            }
        }
        return anc[x][0];
    }
}g;
bool solve( const vector<lint>& ve,const lint anc ){
    for( lint i = 0;i < ve.size();i++ ){
        if( g.solve( ve[i],anc ) == anc ){
            return false;
        }
    }
    return true;
}
int main(){
    lint n,x,y,num;
    scanf("%d",&n);
    init();
    g.init();
    for( lint i= 1;i <= n-1;i++ ){
        scanf("%d%d",&x,&y);
        add( x,y );
        add( y,x );
    }
    g.bfs();
    scanf("%d",&num);
    while( num-- ){
        vex.clear();
        vey.clear();
        lint p,q;
        scanf("%d%d",&p,&q);
    for(  lint i = 1;i <= p;i++ ){
        scanf("%d",&x);
        vex.push_back( x );
    }
    for( lint i = 1;i <= q;i++ ){
        scanf("%d",&y);
        vey.push_back( y );
    }
    lint ancx = vex[0];
    for( lint i = 0; i < vex.size();i++ ){
        x = vex[i];
        ancx = g.solve( x,ancx );
    }
    lint ancy = vey[0];
    for( lint  i = 0;i < vey.size();i++ ){
        y = vey[i];
        ancy = g.solve( y,ancy );
    }
    LL anc = g.solve( ancx,ancy );
    if( anc != ancx && anc != ancy ){
        printf("YES\n");
        continue;
    }
    bool flag = true;
    if( ancx ==anc ){
        flag = solve( vex,ancy );
    }else{
        flag = solve( vey,ancx );
    }
    if( flag ){
        printf("YES\n");
    }else{
        printf("NO\n");
    }
    }
    return 0;
}

F。排序优化枚举。注意写法,vector的second提供索引,所有值都去原数组中去找。下标改为从0开始。

#include <bits/stdc++.h>
using namespace std;
typedef int lint;
typedef long long LL;
typedef pair<lint,lint> pii;
const lint maxn = 300000 + 10;
lint a[maxn],h[maxn];
vector<pii> vea,veh;
priority_queue<pii> que;
int main()
{
    lint n,ans = 0,ansx = 1,ansy = 2;
    scanf("%d",&n);
    for( lint i = 0;i < n;i++ ){
        scanf("%d%d",&a[i],&h[i]);
        vea.push_back( pii( a[i],i ) );
        veh.push_back( pii( h[i],i ) );
    }
    sort( vea.begin(),vea.end() );
    sort( veh.begin(),veh.end() );
    lint p = 0;

    for( lint i = 0;i < vea.size();i++ ){
        pii x = vea[i];
        while( p < n && vea[i].first >= veh[p].first ){
            pii y = veh[p];
            que.push( pii( a[ y.second ],y.second ) );
            p++;
        }
        if( !que.size() ) continue;
        pii y = que.top();
        pii t;
        bool flag = true;
        if( y.second == x.second ){
            flag = false;
            t = y;
            que.pop();
            if( !que.size() ){
                que.push( t );
                continue;
            }
            y = que.top();
        }
        lint re = y.first;
        if( re >= h[ x.second ] ) re += a[ x.second ];
        if( re > ans ){
            ans = re;
            ansx = x.second+1;
            ansy = y.second + 1;
        }
    }
    printf("%d\n",ans);
    printf("%d %d\n",ansx,ansy);
    return 0;
}

 

 

E。贪心策略同活动安排问题。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;
typedef pair<pii,LL> piii;
priority_queue<piii> que1,que2;
vector<LL> ans;
LL m;
bool solve(  ){
    LL cur = m;
    while( cur >= 1 ){
        while( que1.size() && que1.top().first.first >= cur ){
            piii x = que1.top();
            que1.pop();
            que2.push( piii(pii ( -x.first.second,-x.first.first ),x.second) );
        }
        if( que2.empty() ) return false;  
        piii x = que2.top();
        que2.pop();
        ans.push_back( x.second );
        if( -x.first.first > cur ) return false;   //这块的判断很重要,容易漏写
        cur = -x.first.first-1;
    }
    return true;
}
int main()
{
    LL n,x,y;
    scanf("%I64d%I64d",&n,&m);
    for( LL i = 1;i <= n;i++ ){
        scanf("%I64d%I64d",&x,&y);
        que1.push( piii(pii(y,x),i) );
    }
    bool flag = solve();
    if(!flag ){
        printf("NO\n");
        return 0;
    }
    printf("YES\n");
    printf("%I64d\n",(LL)ans.size());
    for( LL i = 0;i < ans.size();i++ ){
        printf("%I64d ",ans[i]);
    }
    return 0;
}

I。一圈一圈走,使得最后重叠的面积最小。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
    LL a,b;
    scanf("%I64d%I64d",&a,&b);
    LL le = a*a - b*b;
    LL c = a % b ;
    le += ( b - c )* c ;
    printf("%I64d",le / b);
    return 0;
}

J。贪心,注意对结构体lowerbound要小心,WA了几次才发现这个问题。

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long LL;
const LL inf = 0x3f3f3f3f3f3f3f3f;
vector<LL> ve1,ve2;
LL summ[500005];
int main()
{
    LL n,x,y,z;
    vector<LL> ve;
    scanf("%I64d",&n);
    for( LL i = 0;i < n;i++ ){
        scanf("%I64d%I64d%I64d",&x,&y,&z);
        ve.clear();
        ve.push_back(x);
        ve.push_back(y);
        ve.push_back(z);
        sort( ve.begin(),ve.end() );
        x = ve[0];y = ve[1];z = ve[2];
        ve1.push_back(  x+y );
        ve2.push_back( x+y+z  );
        summ[i] = x+y;
    }
    sort( ve1.begin(),ve1.end() );
    for( LL i = 0;i < n;i++ ){

        LL sum = ve2[i];
        LL cnt = upper_bound( ve1.begin(),ve1.end(),sum-2 ) - ve1.begin();
        if( summ[i] <= sum - 2 ) cnt--;
        printf("%I64d ",cnt);
    }
    return 0;
}

K。向一个日本的黄名大佬要的代码。

     这题需要倒着想,其实这一点我想到了。但是我没有想到可以根据目标直接从原字符串中直接抽离出子串。

     这末做的道理就在于连续性,开头一旦确定了,后来就都确定了。这个东西好熟悉啊,拓扑序搜索的典范?

 

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
string str;
LL vis[10000];
bool solve(string s){
    string tar;
    for( char c : s ){
        for( char cc : str ){
            if( c == cc ) tar += c;
        }
    }
    LL pos = 0;
    memset( vis,0,sizeof( vis ) );
    LL len = str.length();
    for( LL i = 0;i < len;i++ ){
        if( str[i] == tar[pos] ){
            pos++;
            vis[i] = 1;
        }
    }
    for( LL i = 0;i < len;i++ ){
        if( vis[i] ) continue;
        if( str[i] == tar[pos] ){
            pos++;
            vis[i] = 1;
        }
    }
    if( pos == len ) return true;
    return false;
}
int main()
{
    cin >> str;
        cout << ( ( solve( "BGR" ) || solve( "BRG" ) || solve( "RBG" ) || solve( "RGB" ) || solve( "GBR" ) || solve( "GRB" ) ) ? "YES" : "NO");
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值