Codeforces Round #785 (Div. 2)

Codeforces Round #785 (Div. 2)

A. Subtle Substring Subtraction

贪心;

#include<bits/stdc++.h>
#define ll long long
 
using namespace std;
 
const int N = 1e6+5,N2 = 1e3+5;
int a[N];
 
 
int main()
{
	int i,j;
	int t;cin>>t;
	while(t--)
	{
		string s;cin>>s;
		int len = s.length();
		int cc1 = 0,cc2 = 0;
		if(len%2 == 0){//偶数 
			for(i = 0;i < len; i++){
				cc1+=(s[i]-'a'+1); 
			}
		}else{
			//不选第一个还是最后一个
			for(i = 1;i < len-1; i++){
				cc1 += (s[i]-'a'+1);
			} 
			if(len!=1)cc1 += max(s[0],s[len-1])-'a'+1;
			cc2 = min(s[0],s[len-1])-'a'+1;
		} 
		if(cc1 > cc2) cout<<"Alice "<<cc1-cc2<<'\n';
		else if(cc2 > cc1) cout<<"Bob "<<cc2-cc1<<'\n';
	}
}

B. A Perfectly Balanced String?

​ 分析了几个例子:ababa,abbab,abcabc后发现如果字符串有cnt个不同的字符,那么在任意位置处长为cnt的子串中,这cnt个字符都必须出现才能保证符合题目要求,否则的话就赢会有有某个字符出现两次或者更多,而某个字符出现次数却是0的情况,那就不合法(题目要求)了。

​ 然后我当时想的是,如果例如abcde后面再跟由这几个字母组成的字符串,如果5个字符出现的顺序和前面这个顺序不一样,那就一定会出现某个子串中某个字符出现0次,而某个字符却出现了两次,例如abcdebacde中bcdeb就是不合法的;那如果第一次出现所有字符的那段子串本就不合法呢?例如abbcdeabcde那这本就不满足任意位置处cnt长度的子串要出现所有cnt个字符了。

​ 然后就a啦。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+5,N2 = 1e3+5;
int a[N];
int main()
{
	int i,j;
	int t;cin>>t;
	while(t--)
	{
		bool used[30] ={0};
		string s;cin>>s;
		
		int len = s.length();
		int cnt = 0;
		for(i = 0;i < len; i++){//先找出不同的字符的个数 
			if(!used[s[i]-'a']){
				cnt++;
			}
			used[s[i]-'a'] = true;
		} 
		
		bool ok = true;
		for(i = cnt;i < len; i++){
			if(s[i] != s[i-cnt]){
				ok = false;
				break;
			}
		}
		puts(ok?"YES":"NO");
	}
}

C. Palindrome Basis

造数啊!这是造数!造数两种方法:dfs,动态规划。

​ 求方案数一般都是动态规划,而这种数字j可以由j-a[i]和a[i]组成就是经典完全背包问题;

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 4e4+10,mod = 1e9+7;
ll a[N],dp[N],cnt;

bool check(int x)
{
	string s = to_string(x);
	int len = s.length();
	int ex = len/2;
	string t = s.substr(ex);
	reverse(t.begin(),t.end());
	s = s.substr(0,ex+(len%2==1));
	return s==t;
}

void initial()//预处理 
{
	for(int i = 1;i < N; i++){
		if(check(i)){
			a[++cnt] = i;//储存回文数 
		}
	}
	
	//完全背包
	dp[0] = 1;
	for(int i = 1;i <= cnt; i++){
		for(int j = 0;j < N; j++){
			if(j >= a[i]){
				//j这个数字可以由a[i]和j-a[i]组合得到 
				dp[j] = (dp[j]%mod+dp[j-a[i]]%mod)%mod;
			}
		}
	} 
}
int main()
{
	initial();
	int i,j;
//	for(i =1;i <= 30; i++) cout<<a[i]<<" ";
//	puts("");
	int t;scanf("%d",&t);
	while(t--)
	{
		int n;scanf("%d",&n);
		cout<<dp[n]%mod<<"\n";//方案数 
	}
}

D. Lost Arithmetic Progression

​ 就是说C是由在A和B中都出现的元素构成的,且A,B,C都等差数列。那现在给出了B,C,我们要找到A有多少种情况。

​ 我们令(st,ex,len,ed)表示等差数列的首项、公差、长度,末项;

首先我们要判断C是否合法,C要合法那C中的每一项都要在B中出现,如下面的情况:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vy91jGjj-1651498545166)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220501213754611.png)]那么:

  • st_C>=st_B且ed_C<=ed_B
  • ex_B%ex_C==0,因为ex_C = lcm(ex_A,ex_B),最小公倍数;
  • (st_C-st_B)%ex_B==0;//保证C是B的子集而不是下面这种情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fhqLaB7U-1651498545168)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220501230835466.png)]

这样便合法,任意一项不满足则不合法,答案为0;

在C合法的情况下,我们来考虑A有多少种数量:

​ 首先,因为C是A和B的公共子集,那A中肯定包含C的每一项,然后在此基础上再去加项,C是合法等差数列,故此时的A也是;

​ 然后A向左扩展,向左扩展那每一项都不能在B中出现才行,否则题目给出的C就是不对的了,所以如果A(此时A=C)能向左扩展那扩展的第一项肯定就要不等于或者小于B的第一项才能扩展,因为C是B的子集(姑且这么说吧),所以A(此时A=C)向左扩展的第一个元素如果在B内那肯定就等于B,不可能是不等于的,否则上图就不对了。所以A如果能向左无线扩展,那向左扩展的第一项就已经在B的第一项还要向左走了,即:

​ st_C-ex_C < st_B,右边同理得ed_C+ex_C>ed_B;

此时A可以无线扩展,数量为无穷,答案为“-1”;

然后再来考虑A不能无限扩展的情况:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7uBcatLK-1651498545169)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220502100342279.png)]

因为A中包含C,那如果C的每一项是A中元素的跳跃项,例如下面,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iXtaJvA4-1651498545169)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20220502100411730.png)]

又因为 e x c ex_c exc% e x a ex_a exa=0,那么 e x a ex_a exa范围也就是 [1, ⌊ e x c ⌋ \lfloor \sqrt{ex_c}\rfloor exc ] ,

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9+7;

ll gcd(ll x,ll y)
{
	return y==0?x:gcd(y,x%y);
}
ll lcm(ll x,ll y)
{
	return x*y/gcd(x,y);
}

int main()
{
    int i,j;
    int t;cin>>t;
    while(t--)
    {
        ll st_b,ex_b,len_b;scanf("%lld%lld%lld",&st_b,&ex_b,&len_b);
        ll st_c,ex_c,len_c;scanf("%lld%lld%lld",&st_c,&ex_c,&len_c);
        ll ed_b = st_b + (len_b-1)*ex_b;
        ll ed_c = st_c + (len_c-1)*ex_c;
        //为0的情况
        if(!(st_c>=st_b&&ed_c<=ed_b) || ex_c%ex_b!=0 || (st_c-st_b)%ex_b!=0){
            puts("0");
        }else if(st_c-ex_c<st_b||ed_c+ex_c>ed_b){
            puts("-1");
        }else{
            ll ans = 0;
            for(ll ex_a = 1;ex_a*ex_a <= ex_c; ex_a++)//A的公差
            {
            	if(ex_c%ex_a == 0){
            		if(lcm(ex_a,ex_b) == ex_c)
            		{
            			ans = (ans+ex_c/ex_a*ex_c/ex_a%mod)%mod;
					}
					if(ex_c/ex_a!=ex_a && lcm(ex_c/ex_a,ex_b)==ex_c)
					{
						ans = (ans+ex_a*ex_a%mod)%mod;
					}
				}
			}
			cout<<ans<<endl;
        }
    }
    return 0;
}
			ans = (ans+ex_c/ex_a*ex_c/ex_a%mod)%mod;
				}
				if(ex_c/ex_a!=ex_a && lcm(ex_c/ex_a,ex_b)==ex_c)
				{
					ans = (ans+ex_a*ex_a%mod)%mod;
				}
			}
		}
		cout<<ans<<endl;
    }
}
return 0;

}










  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值