前缀a的数量,后缀c的数量,遇到b就计算一次答案。
#include
using namespace std;
typedef long long ll;
const int N = 1e5+100;
char s[N];
int cnt[N];
int main()
{
ll ans= 0 ;
scanf("%s",s+1);
int n = strlen(s+1);
for(int i=n;i>=1;i--){
if(s[i]=='c') cnt[i] = cnt[i+1] +1;
else cnt[i] = cnt[i+1];
}
int tmp =0 ;
for(int i=1;i<=n;++i){
if(s[i]=='a') tmp++;
else if(s[i]=='b') ans+=1ll*tmp*cnt[i];
}
printf("%lld\n",ans);
}
预处理出每个字符后面26个字母第一次出现的位置。
#include
using namespace std;
typedef long long ll;
const int N = 1e5+100;
char s[N];
int pos[26][N],cnt[26],cur[N][26];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
pos[s[i]-'a'][++cnt[s[i]-'a']]=i;
for(int i=0;i<=n;i++){
for(int j=0;j<26;j++){
int t = upper_bound(pos[j]+1,pos[j]+cnt[j]+1,i) - pos[j];
if(t!=cnt[j]+1) cur[i][j]=pos[j][t];
}
}
while(m--){
char t[60];
scanf("%s",t+1);
int now = 0, len = strlen(t+1),flag=1;
for(int i=1;i<=len;i++){
if(cur[now][t[i]-'a']!=0) now = cur[now][t[i]-'a'];
else {
flag=0;
break;
}
}
puts(flag?"YES":"NO");
}
}
这题比赛时一脸懵逼。周大佬说是以前打过的一道网络赛原题,好吧,忘记了。搜了一波题解。
#include
using namespace std;
typedef long long ll;
int main()
{
ll n;
cin>>n;
if(n<=2) puts("-1");
else {
ll b,c;
if(n % 2){
b = (n*n-1)/2;
c = (n*n+1)/2;
}else {
b = (n*n/2-2)/2;
c = (n*n/2+2)/2;
}
printf("%lld %lld\n",c,b);
}
}
#include
using namespace std;
typedef long long ll;
int main()
{
ll n;
cin>>n;
if(n<=2) puts("-1");
else {
ll b,c;
if(n%2==0){
b = (n*n + 4)/4;
c = b-2;
}else{
b = (n*n + 1)/2;
c = b - 1;
}
printf("%lld %lld\n",c,b);
}
}
解法一:
比赛时想的是贪心暴力。对于每一个位置记录能被哪些羊儿吃以及羊儿能吃到的左端点,然后对这些左端点进行从小到大排序。每次询问一个区间时,怎样给每个位置i分配羊儿呢?贪心选左端点最近的,假设现在有两个端点L1,L2,L1 解法二: 其实这就是一个二分图,对于羊儿能到达区间的每一个点建一条边,然后在询问区间内跑一遍匈牙利就行了。 比赛时想到了一定会是一个大的循环节,但是对于剩下的部分位置不知道咋分配。。。 定义 1 2 3 ... k 为一段。那么我们就是要在n个位置构造sum段这样的1~k。 能得到的答案就是n - sum。所以sum越小,答案就越大。 #include
#include
E-数列
设这sum段中长度最小的段长度为mn,长度最大的段长度为mx,可以发现如果我们已知了sum,那么要使这sum段的总和最小,就要使得mn和mx尽可能的接近,因为如果mx-mn>=2,那么段mx的最后一个元素的值为mx,段mn最后一个元素的值为mn,那么我们使段mx的长度-1,mn的长度加1。那么总和的变化就是总和=总和-mx+mn+1。因为mx-mn>=2,所以mx>mn+1。#include