目录
B Element Swapping
【题意】已知交换前数列的x,y,该数列某两个位置互换后得到给定数列,根据x,y计算现数列由原序列交换位置的方案数。
【解题思路】推公式题。将原序列的x,y值设为x1,y1,现序列的x,y值设为x2,y2,设互换了p,q两个位置,易得以下两个等式dx=x2-x1=(p-q)(ap-aq)与dy=y2-y1=(p-q)(ap^2-aq^2),两式联立后易得dy=dx*(ap+aq),所以遍历一遍数组,对于每个树都能得到一个可以与她交换的数,再判断一下是否成立即可。对啦dx==0 &&dy==0的情况是只要数列中相同的数交换都可以,记得一定要特判,不然一直浮点错误。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
LL a[maxn],tot[maxn],c[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
LL x1=0,y1=0,x2=0,y2=0,ans=0;
memset(tot,0,sizeof(tot));
scanf("%d%lld%lld",&n,&x1,&y1);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
tot[a[i]]++;
x2+=1LL*i*a[i];
y2+=1LL*i*a[i]*a[i];
}
LL dx=x2-x1,dy=y2-y1;
if(dx==0 && dy==0)
{
for(int i=1;i<=100000;i++)
{
if(tot[i]>1)
ans+=(tot[i]*(tot[i]-1))/2LL;
}
}
else if(dx!=0 && dy!=0)
{
if(dy%dx==0)
{
LL p=dy/dx;
for(int i=1;i<=n;i++)
{
if(a[i]<p)
{
LL t=a[i]-(p-a[i]);
//printf("t=%lld\n",t);
if(t!=0 && dx%t==0)
{
int q=i-(dx/t);
if(q>i&& q<=n&&a[q]==p-a[i])ans++;
}
}
}
}
}
printf("%lld\n",ans);
}
}
E Sequence in the Pocket
【题意】给一个长度为n的数组,每次操作可以把一个数放到最前面,问最少几次操作可以使这个数组变成非递减数列。
【解题思路】签到题,排序后倒序查找即可。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int a[maxn],b[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int cnt=0,n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b,b+n);
int t=n-1;
for(int i=n-1;i>=0;i--)
{
if(a[i]==b[t])
{
t--;
cnt++;
}
}
printf("%d\n",n-cnt);
}
}
F Abbreviation
【题意】除单词的首字母外,去除原因字母。
【解题思路】签到题。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
char a[maxn],b[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
string s1,s2;
cin>>s1;
s2=s1[0];
for(int i=1;i<s1.size();i++)
{
if(s1[i]=='a' ||s1[i]=='e'||s1[i]=='i' ||s1[i]=='y'||s1[i]=='o' ||s1[i]=='u')continue;
s2=s2+s1[i];
}
cout<<s2<<endl;
}
}
G Lucky 7 in the Pocket
【题意】找一个大于等于n的,能被7整除但不能被4整除的最小整数。n<=100。
【解题思路】签到题。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
char a[maxn],b[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=n;i<=500;i++)
{
if(i%7==0 && i%4!=0)
{
printf("%d\n",i);
break;
}
}
}
}
H Singing Everywhere
【题意】给n个数,最多可以删去一个数使这个数列中的峰值出现次数最少。
【解题思路】签到题。先把峰值位置都找出来,分类讨论一下即可。
(1)当峰值位置只相隔1个位置时,且两个峰值一样大时,删去中间那个数达到最优,ans-2。
(2)其余只要判断一下前后的大小关系,最多只可能-1。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
long long a[maxn],b[maxn];
vector<int>v;
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
v.clear();
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<n-1;i++)
{
if(a[i]>a[i-1] && a[i]>a[i+1])v.push_back(i);
}
int ans=v.size(),f=0;
if(v.size()>=1)
{
for(int i=0;i<v.size()-1;i++)
{
if(v[i]+2==v[i+1])
{
if(a[v[i]]==a[v[i+1]])
{
ans-=2;
f=1;
break;
}
}
}
if(!f)
{
for(int i=0;i<v.size();i++)
{
long long t1=a[v[i]-1],t2=a[v[i]],t3=a[v[i]+1];
//printf("t1=%lld t2=%lld t3=%lld\n",t1,t2,t3);
if(t1>t3)
{
if(v[i]-2>=0)
{
int t0=a[v[i]-2];
if(t0<t2)continue;
else
{
ans--;
break;
}
}
else
{
ans--;
break;
}
}
else if(t1<t3)
{
if(v[i]+2<n)
{
int t4=a[v[i]+2];
if(t4<t2)continue;
else
{
ans--;
break;
}
}
else
{
ans--;
break;
}
}
else
{
ans--;
break;
}
}
}
}
printf("%d\n",ans);
}
}
I Fibonacci in the Pocket
【题意】求斐波那契数列的第a到第b项和为奇数还是偶数。
【解题思路】签到题。因为斐波那契数列的特征是奇 奇 偶 奇 奇 偶……即3的倍数即为偶数,所以只需要判断a和b被3除的情况即可。不需要大数,只需要将该数的每一位加起来除3即可。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
char a[maxn],b[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s%s",a,b);
int suma=0,sumb=0,la=strlen(a),lb=strlen(b);
for(int i=0;i<la;i++)
suma+=a[i]-'0';
for(int i=0;i<lb;i++)
sumb+=b[i]-'0';
suma%=3;
sumb%=3;
if(suma==0)
{
if(sumb==0)printf("0\n");
else if(sumb==1)printf("1\n");
else if(sumb==2)printf("0\n");
}
else if(suma==1)
{
if(sumb==0)printf("0\n");
else if(sumb==1)printf("1\n");
else if(sumb==2)printf("0\n");
}
else
{
if(sumb==0)printf("1\n");
else if(sumb==1)printf("0\n");
else if(sumb==2)printf("1\n");
}
}
}
J Welcome Party
【题意】有n个人,m对朋友,如果某个人的一个朋友已经进去了,那么他就不会不开心,如果里面一个朋友都没有,他就会不开心,求最少的不开心人数以及进入的最小序列(然而比赛的时候读成一个人只有当它的所有朋友进去了他才会开心……)。
【解题思路】并查集找一下连通块,连通块个数即为答案,再用优先队列维护一下即可输出最小序列。(坑点是卡时间……)
【代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int pre[maxn],vis[maxn],n,m,ans,ans1[maxn],tot;
vector<int>v[maxn];
int findroot(int x)
{
return pre[x]==x?x:pre[x]=findroot(pre[x]);
}
void bfs()
{
priority_queue<int,vector<int>,greater<int> >pq;
for(int i=1;i<=n;i++)
{
if(pre[i]==i)
{
ans++;
pq.push(i);
vis[i]=1;
}
}
while(!pq.empty())
{
int t=pq.top();
pq.pop();
ans1[tot++]=t;
for(int i=0;i<v[t].size();i++)
{
if(!vis[v[t][i]])
{
pq.push(v[t][i]);
vis[v[t][i]]=1;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ans=0;
tot=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
pre[i]=i,v[i].clear(),vis[i]=0;
while(m--)
{
int uu,vv;
scanf("%d%d",&uu,&vv);
v[uu].push_back(vv);
v[vv].push_back(uu);
int fa=findroot(uu);
int fb=findroot(vv);
if(fa!=fb)
{
if(fb<fa)pre[fa]=fb;
else pre[fb]=fa;
}
}
bfs();
printf("%d\n",ans);
printf("%d",ans1[0]);
for(int i=1;i<tot;i++)
printf(" %d",ans1[i]);
printf("\n");
}
}
K Strings in the Pocket
【题意】给一个字符串s和t,询问s的子串翻转后得到t的方案数。
【解题思路】当s和t相等时,需要用马拉车算法,马拉车算法用于求字符串的回文串,p[i]表示以位置i为中心的回文串的长度;当s和t不相等时,设置指针l和r,分别找到第一个s字符串和t字符串中s[l]和t[l]、s[r]和t[r]不等的位置,然后一直往外扩即可。
【代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=2e6+5;
LL p[maxn*2];
LL ans;
int len;
char s[maxn],tmp[maxn*2],t[maxn];
/*
void init()
{
int len=2;
ts[0]='$';
ts[1]='#';
for(int i=0;i<strlen(s);i++)
{
ts[len++]=s[i];
ts[len++]='#';
}
ts[len]='\0';
}
void Manacher()
{
init();
int id,mx=0,len=strlen(ts);
for(int i=1;i<len;i++)
{
if(i<mx)
p[i]=min(p[2*id-i],mx-i);
else p[i]=1;
while(ts[i-p[i]]==ts[i+p[i]])
p[i]++;
if(mx<i+p[i])
{
id=i;
mx=i+p[i];
}
//printf("%d\n",p[i]);
ans+=p[i]/2LL;
}
}*/
void manacher()
{
LL mx=0,pos=0;
for(LL i=1;i<len;i++){
if(i<mx) p[i]=min(p[2*pos-i],mx-i);
else p[i]=1LL;
while(tmp[i-p[i]]==tmp[i+p[i]]) p[i]++;
if(mx<i+p[i]){
pos=i;
mx=i+p[i];
}
}
}
void init()
{
tmp[0]='@'; tmp[1]='#';
int j=2;
for(int i=0;i<len;i++){
tmp[j++]=s[i];
tmp[j++]='#';
}
tmp[j]='\0';
len=j;
manacher();
ans=0;
for(int i=0;i<j;i++)
ans+=p[i]/2LL;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
//memset(ts,0,sizeof(ts));
ans=0;
scanf("%s%s",t,s);
len=strlen(s);
if(strcmp(s,t)==0) init();
else
{
int l=0,r=strlen(s)-1;
while(s[l]==t[l])l++;
while(s[r]==t[r])r--;
int tl=l,tr=r;
if(l<r)
{
while(s[tl]==t[tr])
{
if(tr==l && tl==r)break;
tl++;tr--;
}
if(tr==l && tl==r)
{
ans=1;
l--;
r++;
while(l>=0 && r<len && s[l]==t[r] && s[r]==t[l])
{
l--;
r++;
ans++;
}
}
}
}
printf("%lld\n",ans);
}
}