Codeforces Global Round 7
题意:给定字符串s,在s中取前缀a、后缀b,要求a+b组成回文串t(a、b可以为空串),同时t的长度不能超过s。求最大长度的t并输出。简单版本的s长度1e5
:一开始脑子不太好使直接上暴力,结果n3直接tle。憨憨还在那里以为哪个地方死循环了(超不自信患者)
思路:因为规定了t只能由前缀和后缀组成,也就是说,a的起始点下标一定是0,b的末点下标一定是len。a与b顺序相接
所以从两边开始找对称的最大,直接加到a上,这一段是固定的(前后缀)。然后就在剩下的中间段上找前后缀中的最大回文串。(暴力)
想不清楚可以看看样例里的第二个:
abcdfdcecba
a中固定的:abc
中间段:dfdce
代码中间while(1)根本没用是sbbbb的产物
int check(string ss){
int l=-1,r=ss.length();
while(ss[l+1]==ss[r-1]&&l+1<=r-1){
l++;
r--;
}
if(l==r||l+1==r)
return 1;
else
return 0;
}
int main(){
int t;
cin>>t;
while(t--){
string s,a,ans;
cin>>s;
s.insert(0,"0");
s+='0';
int l,r;
while(1){
int len=s.length()-2;
//cout<<"111 "<
l=0,r=len+1;
while(s[l+1]==s[r-1]&&l+1<r-1){
l++;
r--;
}
if(l==0){
for(int i=len;i>=1;i--){
string tt,rtt;
tt+=s.substr(1,i);
rtt+=s.substr(len+1-i,i);
//cout<<"222 "<
if(check(tt)){
string b;
b+=a;
reverse(b.begin(),b.end());
ans=a+tt+b;
break;
}
if(check(rtt)){
string b;
b+=a;
reverse(b.begin(),b.end());
ans=a+rtt+b;
break;
}
}
break;
}
a+=s.substr(1,l);
if(len-2*l==0){
string b;
b+=a;
reverse(b.begin(),b.end());
ans=a+b;
break;
}
string temp;
swap(temp,s);
s+='0';
s+=temp.substr(l+1,len-2*l);
s+='0';
}
cout<<ans<<endl;
}
return 0;
}
题意:和easy版本一样,但是字符串的数据范围扩大到了1e6,暴力试探回文串基本上是爆了的。
思路:优化中间段的回文串判断,把o(n2)降到o(n).
manacher
这是一个不成熟的连接
大半夜cf突然判不了这个代码我不知道过没过啊
re一波以后过了哈哈我服了ts一定要开char类型,要不manacher会越界
int cnt[maxn*2];
char ts[maxn*2];
void manacher(string s,int len){
int l=0;
ts[l++]='$';
ts[l++]='#';
for(int i=0;i<len;i++){
ts[l++]=s[i];
ts[l++]='#';
}
ts[l]=0;
int maxr=0,flag=0;
for(int i=0;i<l;i++){
cnt[i]=maxr>i?min(cnt[2*flag-i],maxr-i):1;
while(ts[i+cnt[i]]==ts[i-cnt[i]])
cnt[i]++;
if(i+cnt[i]>maxr){
maxr=i+cnt[i];
flag=i;
}
}
return;
}
int main(){
int t;
cin>>t;
while(t--){
string s,a,ans;
cin>>s;
s.insert(0,"0");
s+='0';
int l,r;
while(1){
int len=s.length()-2;
//cout<<"111 "<
l=0,r=len+1;
while(s[l+1]==s[r-1]&&l+1<r-1){
l++;
r--;
}
if(l==0){
string tt=s.substr(1,len);
manacher(tt,len);
int maxxp=0,maxxn=0;
for(int i=1;i<=2*len;i++){
if(cnt[i]==i){
maxxp=max(maxxp,cnt[i]-1);
}
if(i+(cnt[i]-1)==2*len+1){
maxxn=max(maxxn,cnt[i]-1);
}
}
string b;
b+=a;
reverse(b.begin(),b.end());
if(maxxp>maxxn)
ans=a+tt.substr(0,maxxp)+b;
else ans=a+tt.substr(len-maxxn,maxxn)+b;
break;
}
a+=s.substr(1,l);
if(len-2*l==0){
string b;
b+=a;
reverse(b.begin(),b.end());
ans=a+b;
break;
}
string temp;
swap(temp,s);
s+='0';
s+=temp.substr(l+1,len-2*l);
s+='0';
}
cout<<ans<<endl;
}
return 0;
}
题意:给定n为输出数字的长度,要求输出的数字不能被其中出现过的数字整除。
ex:6(×)能被6整除 12(×)能被1、2整除
思路:简单构造题,A我想的是用5和4,用4结尾就保证不被5整除,4前面加个5就能保证不被4整除。B看了其他代码有用2和3的,开头一个2其余全是3,保证奇性同时不被3整除
int main(){
int t=ird();
while(t--){
int n=ird();
if(n==1){
cout<<-1<<endl;
continue;
}
if(n%2==0){
for(int i=1;i<=n/2;i++)
cout<<"54";
cout<<endl;
}
else
{
for(int i=1;i<=n/2;i++)
cout<<"45";
cout<<"4"<<endl;
}
}
return 0;
}
不想说辽我好困
int a[maxn],b[maxn];
int main(){
int n=ird();
for(int i=1;i<=n;i++){
b[i]=ird();
}
int maxx=0;
for(int i=1;i<=n;i++){
maxx=max(maxx,a[i-1]);
a[i]=b[i]+maxx;
cout<<a[i]<<" ";
}
cout<<endl;
return 0;
}
题意:给定1-n的排列,取k个不相交区间。让所有区间的最大值相加最大,输出最大值和不同分区数量。
思路:组合数学。取的区间最大数字为n~n-k+1,第一个答案就是等差数列求和。现在问题就转化成了:已经把选定的数字放在了数组中,如何分区?
下标和数字大小记录,按数字大小排列。分区数就是中间数字个数的乘积。(手推一下就好)
struct node{
LL num;
LL id;
}a[maxn];
bool cmp(node aa,node ab){
return aa.num>ab.num;
}
int main(){
LL n=lrd(),k=lrd();
for(int i=1;i<=n;i++){
a[i].num=lrd();
a[i].id=1ll*i;
}
sort(a+1,a+1+n,cmp);
vector<LL> v;
LL ans=1,co=0;
for(int i=1;i<=k;i++){
co+=a[i].num;
v.push_back(a[i].id);
}
sort(v.begin(),v.end());
for(int i=0;i<k-1;i++)
ans=(ans*(v[i+1]-v[i]))%MOD;
cout<<co<<" "<<ans<<endl;
return 0;
}