A. Two Substrings
题目链接
http://codeforces.com/contest/550/problem/A
题目大意
给你一个字符串,问这个字符串里是否同时包含两个子串’AB’和’BA’
思路
题目范围很小,因此我们可以直接先暴力求出每个’AB’和’BA’所在的位置,然后暴力看是否存在一对’AB’和’BA’互相没有覆盖即可。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 110000
using namespace std;
typedef pair<int,int>pr;
char s[MAXN];
int totA=0,totB=0;
pr prA[MAXN],prB[MAXN];
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=len;i++)
{
if(s[i]=='A'&&s[i+1]=='B')
{
prA[++totA]=make_pair(i,i+1);
continue;
}
if(s[i]=='B'&&s[i+1]=='A')
{
prB[++totB]=make_pair(i,i+1);
continue;
}
}
for(int i=1,p=1;i<=totA;i++)
{
for(;p<=totB;p++)
if(prB[p].first!=prA[i].first&&prB[p].second!=prA[i].second&& prB[p].second!=prA[i].first&&prB[p].first!=prA[i].second)
{
printf("YES\n");
return 0;
}
}
for(int i=1,p=1;p<=totB;p++)
{
for(;i<=totA;i++)
if(prB[p].first!=prA[i].first&&prB[p].second!=prA[i].second&& prB[p].second!=prA[i].first&&prB[p].first!=prA[i].second)
{
printf("YES\n");
return 0;
}
}
printf("NO\n");
return 0;
}
B. Preparing Olympiad
题目链接
http://codeforces.com/contest/550/problem/B
题目大意
给你
n
个数
思路
直接暴力枚举数字的子集即可
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 110
#define INF 0x3f3f3f3f
using namespace std;
typedef pair<int,int>pr;
typedef long long int LL;
int diff[MAXN],n,L,R,mindiff;
int main()
{
scanf("%d%d%d%d",&n,&L,&R,&mindiff);
for(int i=0;i<n;i++) scanf("%d",&diff[i]);
int ans=0;
for(int S=1;S<(1<<n);S++)
{
int minDif=INF,maxDif=-INF,sum=0;
for(int i=0;i<n;i++)
if(S&(1<<i))
{
sum+=diff[i];
minDif=min(minDif,diff[i]);
maxDif=max(maxDif,diff[i]);
}
if(sum>=L&&sum<=R&&maxDif-minDif>=mindiff) ans++;
}
printf("%d\n",ans);
return 0;
}
C. Divisibility by Eight
题目链接
http://codeforces.com/contest/550/problem/C
题目大意
给你一个长度不超过100位的十进制数,问是否可以从中删除一些数位,使得修改后的数字可以被8整除,并输出一组可行解。
思路
注意到长度大于等于四位的8的倍数的特征:末三位数构成的不含前导零的数字是八的倍数。
因此最终我们最多只需要从这个数字里提取3个数位来构成一个新的数字。
因此我们可以
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 110
#define INF 0x3f3f3f3f
using namespace std;
char s[MAXN];
int cnt[12],num[MAXN],len;
bool deled[MAXN];
int ans[110];
bool isBeishu[110000];
void solve1()
{
int tot=0;
for(int i=1;i<=len;i++)
for(int j=i+1;j<=len;j++)
for(int k=j+1;k<=len;k++)
{
if(!num[i]) continue;
int nownum2=num[i]*100+num[j]*10+num[k];
if(isBeishu[nownum2])
{
printf("YES\n%d\n",nownum2);
return;
}
}
for(int i=1;i<=len;i++)
for(int j=i+1;j<=len;j++)
{
if(!num[i]) continue;
int nownum2=num[i]*10+num[j];
if(isBeishu[nownum2])
{
printf("YES\n%d\n",nownum2);
return;
}
}
for(int i=1;i<=len;i++)
if(isBeishu[num[i]])
{
printf("YES\n%d\n",num[i]);
return;
}
printf("NO\n");
}
void solve2()
{
for(int S=1;S<(1<<len);S++) //!!!!!
{
int nownum=0;
for(int i=1;i<=len;i++)
if(S&(1<<(i-1)))
{
nownum*=10;
nownum+=num[i];
}
if(isBeishu[nownum])
{
printf("YES\n%d\n",nownum);
return;
}
}
printf("NO\n");
}
int main()
{
for(int i=0;i<=20000;i+=8) isBeishu[i]=true;
scanf("%s",s+1);
len=strlen(s+1);
for(int i=1;i<=len;i++) num[i]=s[i]-'0',cnt[num[i]]++;
/*if(cnt[0])
{
printf("YES\n0\n");
return 0;
}*/
int rest=0;
if(len>=4)
solve1();
else solve2();
return 0;
}
D. Regular Bridge
题目链接
http://codeforces.com/contest/550/problem/D
题目大意
要求你构造一个简单无向图,使得图里最少包含一条桥边,且图里每个点度数均为 K
思路
存在多条桥边的情况下,我们只需要保留其中一条桥边,根据这条桥边把整个图划分成AB两个联通块,显然两个联通块是对称的,这样我们只需要构造其中一个联通块即可,在构造过程中,也可以把其他的桥边构造出来。
手玩一下可以发现
考虑构造这个联通块,块中有一个点度数为
K−1
,其他点度数均为
K
,根据握手定理,这个联通块的边数为
然后下面的问题就变为,给定了 K+2 个点的度数,构造一个图。这是非常经典的问题,在WC 2015上讲过。具体做法是,每次让剩余度数最大的点,按照剩余度数降序排序,连接其他点,直到这个点的剩余度数用完。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define MAXN 110
#define INF 0x3f3f3f3f
using namespace std;
int K;
vector<pair<int,int> >vec;
int degree[MAXN],rank[MAXN];
bool cmp(int a,int b)
{
return degree[a]>degree[b];
}
int main()
{
scanf("%d",&K);
int T=K+2;
if(!(K&1))
{
printf("NO\n");
return 0;
}
printf("YES\n");
if(K==1)
{
printf("2 1\n1 2\n");
return 0;
}
printf("%d %d\n",(K+2)<<1,(K+2)*K);
for(int i=1;i<=T;i++) degree[i]=K;
for(int i=1;i<=T;i++) rank[i]=i;
degree[1]--;
for(int i=1;i<=T;i++)
{
sort(rank+1,rank+T+1,cmp);
for(int j=2;j<=degree[rank[1]]+1;j++)
{
vec.push_back(make_pair(rank[1],rank[j]));
degree[rank[j]]--;
}
degree[rank[1]]=0;
}
printf("%d %d\n",1,T+1);
for(int i=0;i<vec.size();i++)
{
printf("%d %d\n",vec[i].first,vec[i].second);
printf("%d %d\n",vec[i].first+T,vec[i].second+T);
}
return 0;
}
E. Brackets in Implications
题目链接
http://codeforces.com/contest/550/problem/E
题目大意
定义一个
→
运算:
要在一个表达式里加上一些括号,使得表达式最后的计算结果变为0
思路
要想让表达式变为0,必须让表达式的后面是0,前面为1,因此我们可以这样构造
其中 an 必须为0,而且可以发现,如果 an 不为0,则绝对无解,我们无论怎样构造括号都无法找出一种解法,因为 an 、或者说是被 an 计算出来的值,永远都在一个表达式的右边而非左边,这样的话表达式的值肯定为1
然后我们要保证
(a1→(a2→(a3...)))
部分为1,要想让表达式为1,要么表达式左右两边都是0,要么表达式右边为1。从最里面的括号向外面计算,最里面的括号要么两个都是0,要么右边的
an−1
是1。考虑一般的情况,即
an−1=1
,那么可以发现除了
an−1,an
是有限制的情况外,其他项均无限制,合法的表达式的每一项应该是这个样子的:
而若最里面的括号两个都是0,则除了 an−2,an−1,an 是有限制的情况外,其他项均无限制,合法的表达式的每一项应该是这个样子的:
而其他情况下,合法的表达式的每一项应该是这个样子的:
排除掉上述三种合法情况后,剩下的非法情况就只有一种了:
找出第一个非0的表达式项的位置,然后特判无解就好了
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define MAXN 110000
#define INF 0x3f3f3f3f
using namespace std;
int n,val[MAXN];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
if(n==1)
{
if(val[1]==1) printf("NO\n");
else printf("YES\n0\n");
return 0;
}
if(val[n]==1)
{
printf("NO\n");
return 0;
}
int p;
for(p=1;p<=n-1;p++)
if(val[p]!=1)
break;
if(p==n-1&&val[n-1]==0&&val[n]==0)
{
printf("NO\n");
return 0;
}
printf("YES\n");
for(int i=1;i<=n-2;i++)
printf("(%d->",val[i]);
printf("%d",val[n-1]);
for(int i=1;i<=n-2;i++)
printf(")");
printf("->0\n");
return 0;
}