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;
}