A:Creep
题意:一个字符串的creepiness为前缀中 |1的数量-0的数量| 最大值,创造一个由n个0,m个1的字符串,使creepiness最小。
input
5 1 1 1 2 5 2 4 5 3 7
output
10 011 0011000 101010101 0001111111
思路:
把n和m看做一个大的,一个小的,前缀为字符串本身时,答案就是 |n-m|。
前面的前缀结果只需要比这个小的话,就能保证最小为|n-m|。也就是只需要1,0,1,0地放即可,随着前缀长度增加,答案为0,1,0,1,2,3,4...|n-m|。
代码:
#define M 100010
int T,n,m;
int a[M];
int main()
{
cin>>T;
while(T--){
cin>>n>>m;
int j=0,i=0;
while(i+j<n+m){
if(j<n) cout<<0,j++;
if(i<m) cout<<1,i++;
}
cout<<endl;
}
return 0;
}
B:Paranoid String
题意:
可以将"01"变成"1","10"变成"0",变换次数不受限制,那么一个字符串有多少字串可以变换后长度为1。
input
5 1 1 2 01 3 100 4 1001 5 11111
output
1 3 4 8 5
思路:只能是多想想哪些情况是可以的,最后结果是:如果有一个"10"或"01",那么前面所有的1和0开头,都可以和这个后面的0结束,且长度不为1的只有这一种情况。
比如:101101
第一个10:前面只有一个1
第二个10,前面有1,0,1,1,
对应的10110、0110、110、10都可。
这是因为对于一个......10
如果1前面是1,那么...110 -> ...10
如果1前面是0,那么...010 -> ...10
代码:
int T,n;
string s;
int main()
{
cin>>T;
while(T--){
cin>>n;
cin>>s;
ll sum=0;
for(int i=1;i<n;i++){
if((s[i-1]-'0')^(s[i]-'0')==1){ //如果为10,01,+前面的数量
sum+=i;
}
}
cout<<sum+n<<endl; //长度为1的是n个
}
return 0;
}
C:Directional Increase
题意:
从1处出发,数组初始化0,长度相同,向右走原地+1,向左走原地-1,问能不能走出给定数组。
input
7 2 1 0 4 2 -1 -1 0 4 1 -4 3 0 4 1 -1 1 -1 5 1 2 3 4 -10 7 2 -1 1 -2 0 0 0 1 0
output
No Yes No No Yes Yes Yes
思路:
不难看出,每次一左一右走,只有右走点+1和左拐点-1。
为了不让当前点出范围1-n,贪心地想,向右一定是有负的就用,向左是有正就用。
那么从前往后加起来,这个和不能<1,因为<1的话就不能往右走了
只有右边没有了才能,和也一定要==0。
代码:
#include<bits/stdc++.h>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define ll long long
#define M 1000005
int T,n;
int a[M];
string solve(){
ll sum=0;
fo(1,n){
sum+=a[i];
if(sum<1&&i!=n) return "NO";
}
if(sum==0) return "YES";
return "NO";
}
int main()
{
cin.tie(nullptr)->sync_with_stdio(false);
cin>>T;
while(T--){
cin>>n;
fo(1,n) cin>>a[i];
while(a[n]==0) n--;
cout<<solve()<<endl;
}
return 0;
}