A. We Got Everything Covered!
找出一个字符串S,满足条件:所有可能的长度为n,使用前k个小写字母的字符串P都是S的子串。
其中字符串S的长度尽可能短。
这种构造题,构造S的时候尽可能在原有的基础上去扩展,如果能扩展出来,那就是有规律。
n=1,k=3
S:abc
n=1,k=4(+1) n=2(+1),k=3
S:abcd S:abcabc
n决定了每个字母最少出现的次数,所以上面的答案均是最短的情况。
AC代码
#include <bits/stdc++.h>
//#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;int n,k;void solve(){cin>>n>>k;per(i,1,n){per(j,1,k){cout<<(char)('a'+j-1);}}cout<<endl;
}void init(){}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);int t;cin>>t;while(t--)solve(),init();return 0;
}
B. A Balanced Problemset?
题意:给你一个数N,拆数拆成X个,计算他们的gcd值为P,在所有拆数的情况里面,输出最大的P值。
思路:最大的P值,即这些被拆开数的最大公约数,既然是公共的约数,那么被拆出来的数一定是有倍数关系的,比如:2 2 4 8(均为2的倍数),3 3 3 3 6(均为3的倍数)。
那显然最好的情况是数N,被拆成X个数后,设N/X=k,如果没有余数p全都相等,那k就是答案。
不可能找出最大的公约数k+1,不然数每个数都要增大一,数N就要变成N+k了。
如果拆出来有余数,那就分两种情况:
1. 余数 p 是 k 的倍数,那 k 就是答案(答案不可能是k+1,余数是小于X的,不可能均摊让所有数+1)
2. 余数 p 不是 k 的倍数,那我们只能考虑更小的答案,即 k--,p+=n(一共有n份数,每份都减一),直到 p 成为 k 的倍数。
#include <bits/stdc++.h>
//#define int long long
#define per(i,j,k) for(int (i)=(j);(i)<=(k);++(i))
#define rep(i,j,k) for(int (i)=(j);(i)>=(k);--(i))
#define fr first
#define se second
#define endl '\n'
using namespace std;int x,n;void solve(){cin>>x>>n;int k=x/n;//均分,每份为kif(k*n==x){//没有余数cout<<k<<endl;return;}else{//有余数,设为pint p=x-(k*n);if(p%k==0){//余数是倍数部分cout<<k<<endl;return;}else{//余数不是倍数//如果不是那就把整体全部缩水1while(p%k!=0){//找到成为倍数为止p+=n;k--;}cout<<k<<endl;return;}}
}void init(){}
signed main(){ios::sync_with_stdio(false),cin.tie(nullptr);int t;cin>>t;while(t--)solve(),init();return 0;
}
这个代码的复杂度可以看出来是k*T,最差情况下k=1e8,T=1e3,总计1e11的复杂度,这道题大概率是过不了的。
T我们没法改变,那就尝试优化一下内部的k。
因为一直在执行k--,所以可以得出一个数学式子
while(p%k!=0){p+=n;k--;}设k一共减去了x使得p成为了k的倍数。
则有(p+x*n)%(k-x)=0即 p+x*n 是 k-x 的倍数p+x*n = y*(k-x)