Codeforces Round #297 (Div. 2)——A.B.C.D.E

http://codeforces.com/contest/525

A. Vitaliy and Pie
从左到右模拟一下

#include<bits/stdc++.h>
const int MAXN=200100;
using namespace std;
string s;
int n;
int key[MAXN];
int main()
{
    scanf("%d",&n);
    cin>>s;
    int l=s.length();
    int cnt=0;
    for(int i=0;i<l;++i){
        if(!(i&1)) key[s[i]-'a']++;
        else{
            if(key[s[i]-'A']) key[s[i]-'A']--;
            else cnt++;
        }
    }
    printf("%d\n",cnt);
    return 0;
}

B. Pasha and String
题目描述:
给定一个字符串s,然后m个操作,对区间[ai,|s|-ai+1]进行翻转,求最后所得的字符串s’

1.可以用splay,贴个模板就行了
2.用一个rev标记预先记录每个位置翻转的次数,然后从位置i~n/2,对每个位置的rev进行判定,swap(s[i],s[l-i+1])

#include<bits/stdc++.h>
const int MAXN=200010;
using namespace std;
int n;
int sum[MAXN];
char s[MAXN];
int main()
{
    scanf("%s",s);
    scanf("%d",&n);
    int x;
    for(int i=1;i<=n;++i){
        scanf("%d",&x);
        sum[x]^=1;
    }
    int l=strlen(s);
    int flag=0;
    for(int i=1;i<=l/2;++i){
        flag^=sum[i];
        if(flag){
            swap(s[i-1],s[l-i]);
        }
    }
    cout<<s<<endl;
    return 0;
}

splay:

#include<bits/stdc++.h>
#define Key_value ch[ch[root][1]][0]
const int MAXN=200100;
const int INF=1<<30;
using namespace std;
int root,tot1,ch[MAXN][2],key[MAXN],pre[MAXN];
int s[MAXN],tot2;
int rev[MAXN],size[MAXN];
int a[MAXN];
char str[MAXN];
int n,m;
void update_rev(int rt){
    if(!rt) return ;
    swap(ch[rt][0],ch[rt][1]);
    rev[rt]^=1;
}
void push_up(int rt){
    int lson=ch[rt][0],rson=ch[rt][1];
    size[rt]=size[lson]+size[rson]+1;
}
void push_down(int rt){
    if(rev[rt]){
        update_rev(ch[rt][0]);
        update_rev(ch[rt][1]);
        rev[rt]=0;
    }
}
void NewNode(int &rt,int f,int k){
    if(tot2) rt=s[tot2--];
    else rt=++tot1;
    ch[rt][0]=ch[rt][1]=0;
    pre[rt]=f;
    key[rt]=k;
    size[rt]=1;
    rev[rt]=0;
}
void build(int &rt,int l,int r,int f)
{
    if(l>r) return ;
    int mid=(l+r)>>1;
    NewNode(rt,f,str[mid]-'a');
    build(ch[rt][0],l,mid-1,rt);
    build(ch[rt][1],mid+1,r,rt);
    push_up(rt);
}
void init()
{
    root=tot1=tot2=0;
    rev[root]=ch[root][0]=ch[root][1]=pre[root]=size[root]=0;
    NewNode(root,0,-1);
    NewNode(ch[root][1],root,-1);
    scanf("%s",str);
    n=strlen(str);
    build(Key_value,0,n-1,ch[root][1]);
    push_up(ch[root][1]);
    push_up(root);
}
void Rotate(int x,int kind)
{
    int y=pre[x];
    push_down(y);
    push_down(x);
    ch[y][!kind]=ch[x][kind];
    pre[ch[x][kind]]=y;
    if(pre[y])
        ch[pre[y]][ch[pre[y]][1]==y]=x;
    pre[x]=pre[y];
    pre[y]=x;
    ch[x][kind]=y;
    push_up(y);
}
void Splay(int x,int goal)
{
    push_down(x);
    while(pre[x]!=goal) {
        if(pre[pre[x]]==goal) {
            Rotate(x,ch[pre[x]][0]==x);
        } else {
            int y=pre[x];
            int kind=ch[pre[y]][0]==y;
            if(ch[y][kind]==x) {
                Rotate(x,!kind);
                Rotate(x,kind);
            } else {
                Rotate(y,kind);
                Rotate(x,kind);
            }
        }
    }
    push_up(x);
    if(goal==0) root=x;
}
int Get_kth(int rt,int k)
{
    push_down(rt);
    int z=size[ch[rt][0]]+1;
    if(z==k) return rt;
    if(z>k) return Get_kth(ch[rt][0],k);
    else return Get_kth(ch[rt][1],k-z);
}
void Reverse(int x,int y)
{
    Splay(Get_kth(root,x),0);
    Splay(Get_kth(root,y+2),root);
    update_rev(Key_value);
}
int cnt;
void InOrder(int rt)
{
    if(!rt) return ;
    push_down(rt);
    InOrder(ch[rt][0]);
    if(cnt>=1&&cnt<=n){
        printf("%c",key[rt]+'a');
    }
    cnt++;
    InOrder(ch[rt][1]);

}
int main()
{
    init();
    int x;
    scanf("%d",&m);
    while(m--){
        scanf("%d",&x);
        Reverse(x,n-x+1);
    }
    cnt=0;
    InOrder(root);
    return 0;
}

C. Ilya and Sticks
题目描述:
有n个木棍,每个木棍都有一个长度,求用其中的木棍组成一些矩形,求所有矩形的和的最大值。可以将每个木棍的长度减1

分析:根据题目,每个矩形只能由4根木棍组成,那么按木棍长度从大到小排序,每次比较相邻的两个木棍的长度差是否小于等于1,满足则取出来

#include<bits/stdc++.h>
typedef long long ll;
const int MAXN=100010;
using namespace std;
ll len[MAXN];
vector<pair<ll,ll> > vl;
int n;
bool cmp(ll a,ll b){
    return a>b;
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;++i) scanf("%I64d",&len[i]);
    sort(len,len+n,cmp);
    int cnt=0;
    for(int i=0;i<n;++i){
        if(len[i]-len[i+1]<=1){
            vl.push_back(make_pair(len[i],len[i+1]));
            i++;
            cnt++;
        }
    }
    if(cnt>=1){
        int l=vl.size();
        if(l&1) l-=1;
        ll sum=0;
        for(int i=0;i<l;i+=2){
            sum+=vl[i].second*vl[i+1].second;
        }
        printf("%I64d\n",sum);
    }else printf("0\n");
    return 0;
}

D. Arthur and Walls
题目描述:
给定一个n*m的地图,求将所有的由’.’组成的连通分量构成一个矩形,所需要删除的最少数量的’#’

取最小单元2*2的正方形,如果满足只有一个点是’#’,其余都是’.’,则将’#’变成’.’
bfs

#include<bits/stdc++.h>
const int MAXN=2020;
using namespace std;
int n,m;
char pic[MAXN][MAXN];
queue<int> q;
int dx[8]={-1,-1,-1,0,0,1,1,1};
int dy[8]={-1,0,1,-1,1,-1,0,1};
bool check(int i,int j){
    if(pic[i][j]=='.'||i>n||i<1||j>m||j<1) return false;

    if(pic[i][j-1]=='.'&&pic[i-1][j-1]=='.'&&pic[i-1][j]=='.') return true;
    if(pic[i][j+1]=='.'&&pic[i-1][j]=='.'&&pic[i-1][j+1]=='.') return true;
    if(pic[i][j-1]=='.'&&pic[i+1][j]=='.'&&pic[i+1][j-1]=='.') return true;
    if(pic[i][j+1]=='.'&&pic[i+1][j]=='.'&&pic[i+1][j+1]=='.') return true;
    return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%s",pic[i]+1);
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            if(check(i,j)){
                q.push(i);
                q.push(j);
            }
        }
    }
    while(!q.empty()){
        int x=q.front();q.pop();
        int y=q.front();q.pop();
        if(!check(x,y)) continue;
        pic[x][y]='.';
        for(int i=0;i<8;++i){
            int nx=x+dx[i];
            int ny=y+dy[i];
            if(check(nx,ny)){
                q.push(nx);
                q.push(ny);
            }
        }
    }
    for(int i=1;i<=n;++i)
        printf("%s\n",pic[i]+1);
    return 0;
}

E. Anya and Cubes
题目描述:
有n个数,k个感叹号,求使用其中的某些数和感叹号,使它们的和为s的方案数
感叹号表示阶乘

暴力枚举,每个数有3种状态,不取,取不使用!,取使用!
那么总共有 325
中途相遇法:用map存储前n/2种的所有可能值,然后再暴力后n/2的所有可能值,在map中查找,那么时间就变成开根号了
详见训练指南58页

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int n,k;
ll s;
ll x[26];
ll fac[20];
ll ans;
map<ll,ll> mp[26];
void init(){
    fac[0]=1;
    for(int i=1;i<=18;++i)
        fac[i]=fac[i-1]*i;
}
void dfs_1(int i,int cnt,ll sum){
    if(cnt>k||sum>s) return ;
    if(i==n/2){
        mp[cnt][sum]++;
        return ;
    }
    dfs_1(i+1,cnt,sum);
    dfs_1(i+1,cnt,sum+x[i]);
    if(x[i]<=18){
        dfs_1(i+1,cnt+1,sum+fac[x[i]]);
    }
}
void dfs_2(int i,int cnt,ll sum){
    if(cnt>k||sum>s) return ;
    if(i==n){
        for(int j=0;j+cnt<=k;++j){
            if(mp[j].count(s-sum)){
                ans+=mp[j][s-sum];
            }
        }
        return ;
    }
    dfs_2(i+1,cnt,sum);
    dfs_2(i+1,cnt,sum+x[i]);
    if(x[i]<=18){
        dfs_2(i+1,cnt+1,sum+fac[x[i]]);
    }
}
int main()
{
    init();
    scanf("%d%d%I64d",&n,&k,&s);
    for(int i=0;i<n;++i){
        scanf("%I64d",x+i);
    }
    dfs_1(0,0,0);
    ans=0;
    dfs_2(n/2,0,0);
    printf("%I64d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值