A-咪咪游戏
Solution
需要满足以下条件:
- 字符串长度为偶数。
- 奇数位是
,偶数位是
。
从前到后扫描一遍即可。
时间复杂度 。
Code
#include <iostream>
#include <cstdio>
#include <cstring>
const int maxn=1e5+10;
using namespace std;
int n,q;
char ch[maxn];
int main(){
ios::sync_with_stdio(false);
cin>>q;
int x;
while(q--){
cin>>(ch+1);
n=strlen(ch+1);
if(n%2==1){
cout<<"No"<<endl;
continue;
}
x=1;
for(int i=1;i<=n;i++)
if((i%2==1&&ch[i]!='m')||(i%2==0&&ch[i]!='q')){
x=0;
break;
}
if(x)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
} B-三角形
Solution
依次处理每个序列。若当前处理到第 个序列,在所有可能的和中只有前
小的可能会对最终答案产生贡献。那么就可以及时剔除其他情况。此过程可以使用大根堆来维护,每次将当前序列和合并成一个大小为
的数组即可。
关于合并两个数组得到新的和,使用的是经典的双指针法。
时间复杂度: 。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e6+10;
int ans,n,m,k,tot,a[maxn],b[maxn],c[maxn];
struct node{
int x,y,z;
}heap[maxn<<1];
void up(int u){
while(u>1){
if(a[heap[u].x]+b[heap[u].y]<a[heap[u>>1].x]+b[heap[u>>1].y])
swap(heap[u],heap[u>>1]);
else
break;
u>>=1;
}
}
void down(int u){
int v=u<<1;
while(v<=tot){
if(v<tot&&a[heap[v+1].x]+b[heap[v+1].y]<a[heap[v].x]+b[heap[v].y])
v++;
if(a[heap[v].x]+b[heap[v].y]<a[heap[u].x]+b[heap[u].y])
swap(heap[u],heap[v]);
else
break;
u=v;
v=u<<1;
}
}
void insert(int i,int j,int q){
heap[++tot].x=i;
heap[tot].y=j;
heap[tot].z=q;
up(tot);
}
void extract(){
heap[1]=heap[tot--];
down(1);
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>k;
m=1;
int len,cnt;
for(int i=1;i<=n;i++){
cin>>len;
cnt=0;
for(int j=1;j<=len;j++)
cin>>b[j];
sort(b+1,b+len+1);
if(i==1)
for(int j=1;j<=len;j++)
a[j]=b[j];
else{
for(int j=1;j<=m;j++)
for(int h=1;h<=len;h++)
c[++cnt]=a[j]+b[h];
for(int j=1;j<=cnt;j++)
a[j]=c[j];
sort(a+1,a+cnt+1);
}
m*=len;
if(m>=k){
m=k,len=i;
break;
}
}
int u,v;
for(int i=len+1;i<=n;i++){
cin>>cnt;
tot=0;
for(int j=1;j<=cnt;j++)
cin>>b[j];
sort(b+1,b+cnt+1);
insert(1,1,0);
for(int j=1;j<=k;j++){
u=heap[1].x;
v=heap[1].y;
c[j]=a[u]+b[v];
if(v+1<=cnt)
insert(u,v+1,1);
if(!heap[1].z)
insert(u+1,v,0);
extract();
}
for(int j=1;j<=k;j++)
a[j]=c[j];
}
for(int i=1;i<=k;i++)
ans+=a[i];
cout<<ans;
return 0;
} C-区间加
Solution
序列问题还是先想差分。设 为第
位还差多少到
,
为
的差分数组。之后依次考虑
:
- 若
,则表明此处比上一处所需要的少
。那么可以在
处放置一个区间右端点。
- 若
,则表明此处比上一处所需要的多
。那么可以在
处放置一个区间左端点。
- 若
,则表明此处和上一处所需要的相等 。那么可以在
处放置一个区间左端点,在
处放置一个区间右端点,也可以都不放。
- 若
或
,显然不可能成功。
所以只需要维护一个变量记录当前未匹配的左端点个数,再根据乘法原理更新答案即可。
时间复杂度: 。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int mod=998244355;
const int maxn=2e3+10;
int n,m,sum,a[maxn],b[maxn];
ll ans=1;
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]=m-a[i];
}
for(int i=1;i<=n+1;i++)
b[i]=a[i]-a[i-1];
for(int i=1;i<=n+1;i++){
if(b[i]>1||b[i]<-1){
ans=0;
break;
}
else if(b[i]==1)
sum++;
else if(!b[i])
ans=(ans*(sum+1))%mod;
else
ans=(ans*sum)%mod,sum--;
}
cout<<ans;
return 0;
} D-多元组
Solution
显然是一道 题。设
表示前
个数组成
元组的方案数,那么有
然后发现这个前缀可以用树状数组维护:设 为小于
的数所能组成的
元组的数量。将数据离散化即可。
时间复杂度: 。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const ll maxn=1e5+10;
const ll mod=1e9+7;
ll n,m,len,a[maxn],b[maxn],c[maxn],ans[maxn][52],t[maxn][52];
ll gtid(ll x){
ll l=1,r=len,mid;
while(l<r){
mid=(l+r)>>1;
if(c[mid]<x)
l=mid+1;
else
r=mid;
}
return l;
}
ll lowbit(ll x){
return x&(-x);
}
ll ask(ll x,ll y){
ll sum=0;
for(;x>0;x-=lowbit(x))
sum=(sum+t[x][y])%mod;
return sum;
}
void add(ll x,ll y,ll z){
for(;x<=len;x+=lowbit(x))
t[x][y]=(t[x][y]+z)%mod;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i];
}
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
if(b[i]!=b[i-1]||i==1)
c[++len]=b[i];
for(int i=1;i<=n;i++)
ans[i][1]=1;
ll x;
for(int i=1;i<=n;i++){
x=gtid(a[i]);
add(x,1,1);
for(int j=2;j<=m;j++){
ans[i][j]=(ans[i][j]+ask(x-1,j-1))%mod;
add(x,j,ans[i][j]);
}
}
ll sum=0;
for(int i=1;i<=n;i++)
sum=(sum+ans[i][m])%mod;
cout<<sum;
return 0;
} 
京公网安备 11010502036488号