第一题:k-String
题意:k-string表示这个字符串可以由子串连续重复k次表示。比如"aabaabaabaab"是1-string,2-string和4-string,
给你一个字符串和一个数字k,问它能不能通过交换两个字符的位置形成k-string,可以的话就输入任意一个解,不可以就输出-1.
题解:如果存在k-string,那么每个字母出现的次数一定是k的倍数,只要判断这个条件就能得出答案。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int count[30];
int main()
{
int k;
char s[1005];
for(bool flag=false; ~scanf("%d%s",&k,s); flag=false)
{
memset(count,0,sizeof(count));
for(int i=0; i<strlen(s); ++i)
count[s[i]-'a']++;
for(int i=0; i<26; ++i)
if(count[i]%k!=0)
{
flag=true;
break;
}
if(flag)
{
puts("-1");
continue;
}
for(int t=0; t<k; ++t)
for(int i=0; i<26; ++i)
for(int j=0; j<count[i]/k; ++j)
printf("%c",'a'+i);
puts("");
}
return 0;
}
第二题:Special Offer! Super Price 999 Bourles!
题意:给两个正整数p和d,问含有最多‘9’的数x(p-d<=x<p)是多少。
题解:从最低位开始,枚举末位出现‘9’最多且小于p的数,如果超过范围,则前一次枚举的数为正解。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
LL a,b,c,tmp;
int main()
{
char s[25];
int num[25]={0};
a=b=tmp=0;
scanf("%s%I64d",s,&b);
int len=strlen(s);
for(int i=0; i<len; ++i)
num[i]=s[i]-'0';
a=0;
for(int i=0; i<len; ++i)
a=(a*10+num[i]);
c=a;
for(int i=len-1,j; i>=0; --i)
{
bool flag=false;
if(num[i]==9) continue;
else
{
for(j=i-1; j>=0; --j)
if(num[j]>0)
{
num[j]--;
flag=true;
break;
}
if(!flag) break;
for(++j; j<i; ++j)
num[j]=9;
num[i]=9;
tmp=0;
for(int i=0; i<len; ++i)
tmp=(tmp*10+num[i]);
if(a-tmp>b) break;
c=tmp;
}
}
printf("%I64d\n",c);
return 0;
}
第三题:Color Stripe
题意:给你两个数字n和k,n代表有n个格子,k代表有k个颜色,再给一个代表当前染色情况的字符串,问最少要修改几个格子使得不存在相邻两个格子是同一种颜色的情况。
题解:贪心。当n等于2时,格子最后一定是ABABAB..或者BABABA..的样子,只要判断改成那哪种样子代价最小即可。
当n大于2时,每当发现连续相同颜色块时,一定是把相同颜色块中偶数位的颜色改为不同与颜色块中第一个的颜色和颜色块之后第一个颜色为最优选择。因为n大于2,所以也一定能找到不同于这两种颜色的第三种颜色。
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
char s[500005];
char check(char a,char b)
{
for(int i = 0; i < 3; ++i)
{
char x= 'A' + i;
if(x!=a && x != b) return x;
}
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
scanf("%s",s);
if(k==2)
{
int a=0,b=0;
for(int i = 0; i < n; ++i)
if((i&1)&&s[i]=='A'||(!(i&1))&&s[i]=='B') a++;
else b++;
printf("%d\n",min(a, b));
for(int i = 0; i < n; ++i)
printf("%c",(a>b)^(i&1)?'B':'A');
puts("");
return 0;
}
int l = 0, r, ans = 0;
for(int i = 0; i < n; i++)
{
if(s[i] != s[i+1] || i == n-1)
{
r = i;
if(l == r)
{
l = r+1;
continue;
}
char x = check(s[i],s[i+1]);
for(int j = l +1; j <= r; j+= 2)
{
s[j] = x;
ans ++;
}
l = r+1;
}
}
printf("%d\n",ans);
printf("%s\n",s);
return 0;
}
第四题:Choosing Capital for Treeland
题意:给你一个有向的树,让你选择一个点使得通过反向一些边让这点能到所以其他的点,同时让需要反向的边最少。
题解:两次树形DP,第一次求子树需要反向的边,第二次累加父树以上需要反向的边,取和的最小值即为答案。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 200005
int edge[MAX<<1];//表示第i条边的终点
int next[MAX<<1];//与第i条边同起点的下一条边的位置
int head[MAX<<1];//以i为起点的第一条边的储存位置
int to[MAX<<1];
int dp[MAX],dpx[MAX];
void insert(int i,int a,int b,int c)//a起点,b终点
{
edge[i]=b;
next[i]=head[a];
to[i]=c;
head[a]=i;
}
void dfs_f(int x,int p)//统计子树的修改次数
{
dp[x]=0;
for(int i=head[x];i!=-1;i=next[i])
{
int k=edge[i];
if(k==p) continue;
dfs_f(k,x);
dp[x]+=(dp[k]+(to[i]==x));
}
}
void dfs_m(int x,int p,int idx)
{
if(p==-1) dpx[x]=dp[x];
else
{
if(to[idx]==x) dpx[x]=dpx[p]+1;
else dpx[x]=dpx[p]-1;
}
for(int i=head[x];i!=-1;i=next[i])
{
int k=edge[i];
if(k==p) continue;
dfs_m(k,x,i);
}
}
int main()
{
memset(head,-1,sizeof(head));
memset(next,-1,sizeof(next));
int n,a,b;
scanf("%d",&n);
for(int i=1,j=1;i<n;++i)
{
scanf("%d%d",&a,&b);
insert(j++,a,b,b);
insert(j++,b,a,b);
}
dfs_f(1,-1);
dfs_m(1,-1,1);
int maxx=0xfffff;
for(int i=1;i<=n;++i)
if(dpx[i]<maxx) maxx=dpx[i];
printf("%d\n",maxx);
for(int i=1;i<=n;++i)
if(dpx[i]==maxx)
printf("%d ",i);
return 0;
}
第五题:Parking Lot
来源:http://blog.youkuaiyun.com/acm_ted/article/details/7922132