Codeforces Round #297 (Div. 二)——A.B.C.D.E
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种状态,不取,取不使用!,取使用!
那么总共有
中途相遇法:用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;
}