20220919--CSP-S模拟7
A. 序列问题
发现本质是让求一个 \(i-a_i\) 的最长不下降子序列
需要满足以下三个条件:
\(\begin{cases} j<i \\ a_j<a_i \\ j-a_j<i-a_i\end{cases}\)
进行一个 \(\operatorname{CDQ}\) 即可
点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=500100;
struct Query{
int x,y,z,ans;
}ask[WR],tmp[WR];
int n,tot,ans;
int a[WR],pos[WR],v[WR];
int tree[WR];
int dp[WR];
bool vis[WR];
int read(){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=(s<<3)+(s<<1)+ch-'0';
ch=getchar();
}
return s*w;
}
bool cmp1(Query x,Query y){
return x.y<y.y;
}
bool cmp2(Query x,Query y){
return x.x<y.x;
}
int lowbit(int x){
return x&(-x);
}
void modify(int k,int val){
for(int i=k;i<=n;i+=lowbit(i)){
// cerr<<i<<endl;
tree[i]=max(tree[i],val);
}
}
void clr(int k){
for(int i=k;i<=n;i+=lowbit(i)) tree[i]=0;
}
int query(int k){
int res=0;
for(int i=k;i;i-=lowbit(i)){
// cerr<<i<<endl;
res=max(res,tree[i]);
}
return res;
}
void CDQ(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
CDQ(l,mid);
sort(ask+mid+1,ask+r+1,cmp1);
int i=l,j=mid+1;
while(j<=r){
while(i<=mid&&ask[i].y<=ask[j].y){
modify(ask[i].x-ask[i].y,ask[i].ans);
i++;
}
ask[j].ans=max(ask[j].ans,query(ask[j].z)+1);
j++;
}
while(i>l){
i--;
clr(ask[i].x-ask[i].y);
}
sort(ask+mid+1,ask+r+1,cmp2);
CDQ(mid+1,r);
merge(ask+l,ask+mid+1,ask+mid+1,ask+r+1,tmp+l,cmp1);
for(i=l;i<=r;i++) ask[i]=tmp[i];
}
signed main(){
// freopen("sequence.in","r",stdin);
// freopen("sequence.out","w",stdout);
n=read();
for(int i=1;i<=n;i++){
int x=read();
if(x>i) continue;
ask[++tot]={i,i-x,x-1,1};
}
CDQ(1,tot);
for(int i=1;i<=tot;i++) ans=max(ans,ask[i].ans);
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
B. 钱仓
点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=1001000;
int n;
int c[WR],sum,st;
int ans;
queue<int>q;
int read(){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=(s<<3)+(s<<1)+ch-'0';
ch=getchar();
}
return s*w;
}
signed main(){
// freopen("barn.in","r",stdin);
// freopen("barn.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) c[i]=c[n+i]=read();
for(int i=1;i<=n;i++){
sum+=c[i];
if(sum<i){
st=i+1;
sum=i;
}
}
// printf("%lld ",st);
// int pos=st-1;
// do{
// printf("%lld\n",pos);
// if(c[pos]==0) q.push(pos);
// else{
// while(c[pos]&&(!q.empty())){
// int u=q.front();q.pop();
// c[pos]--;
// ans+=(pos-u)*(pos-u);
// }
// if(!c[pos]) q.push(pos);
// }
// pos--;
// pos=(pos-1+n)%n+1;
// }while(pos!=st-1);
//好像只能顺时针
for(int i=st+n-1;i>=st;i--){
if(c[i]==0) q.push(i);
else{
while(c[i]&&(!q.empty())){
int u=q.front();q.pop();
c[i]--;
ans+=(i-u)*(i-u);
}
if(!c[i]) q.push(i);
}
}
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
C. 自然数
点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=1001000;
struct SegmentTree{
int l,r,val,minval,lzy;
}tree[WR<<2];
int n,a[WR];
int plc[WR],nxt[WR],rec[WR];
bool vis[WR];
int ans;
int read(){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=(s<<3)+(s<<1)+ch-'0';
ch=getchar();
}
return s*w;
}
void pushup(int k){
tree[k].val=tree[k<<1].val+tree[k<<1|1].val;
tree[k].minval=min(tree[k<<1].minval,tree[k<<1|1].minval);
}
void pushdown(int k){
tree[k<<1].lzy=tree[k<<1|1].lzy=tree[k].lzy;
tree[k<<1].minval=tree[k<<1|1].minval=tree[k].minval;
tree[k<<1].val=tree[k].lzy*(tree[k<<1].r-tree[k<<1].l+1);
tree[k<<1|1].val=tree[k].lzy*(tree[k<<1|1].r-tree[k<<1|1].l+1);
tree[k].lzy=-1;
}
void build(int k,int l,int r){
// cerr<<k<<" "<<l<<" "<<r<<endl;
tree[k].l=l,tree[k].r=r;
tree[k].lzy=-1;
if(l==r){
tree[k].val=tree[k].minval=rec[l];
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
void modify(int k,int l,int r,int val){
if(tree[k].l>=l&&tree[k].r<=r){
tree[k].val=val*(tree[k].r-tree[k].l+1);
tree[k].minval=tree[k].lzy=val;
return;
}
if(tree[k].lzy!=-1) pushdown(k);
int mid=(tree[k].l+tree[k].r)>>1;
if(l<=mid) modify(k<<1,l,r,val);
if(r>mid) modify(k<<1|1,l,r,val);
pushup(k);
}
int query_mex(int k,int pos){
if(tree[k].l==tree[k].r){
if(tree[k].minval>=pos) return tree[k].l;
else return n+1;
}
if(tree[k].lzy!=-1) pushdown(k);
if(tree[k<<1|1].minval<pos) return query_mex(k<<1|1,pos);
else return min(tree[k<<1|1].l,query_mex(k<<1,pos));
return n+1;
}
signed main(){
freopen("mex.in","r",stdin);
freopen("mex.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) a[i]=read(),nxt[i]=n+1;
int pos=0;
for(int i=1;i<=n;i++){
if(a[i]<WR) vis[a[i]]=true;
while(vis[pos]) pos++;
ans+=pos;
rec[i]=pos;
}
for(int i=1;i<=n;i++){
if(a[i]<WR){
nxt[plc[a[i]]]=i;
plc[a[i]]=i;
}
}
build(1,1,n);
for(int i=1;i<n;i++){
modify(1,i,i,0);
int mex=query_mex(1,a[i]+1);
if(mex<nxt[i]) modify(1,mex,nxt[i]-1,a[i]);
ans+=tree[1].val;
}
printf("%lld\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
D. 环路
一眼考虑矩阵
可以给 \(i\) 和 \(i+n\) 连边再给 \(i+n\) 和 \(i+n\) 连边
这样你每次统计的答案就全部放到 \(i+n\) 上去了
然后就可以直接矩阵快速幂了
点击查看代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=205;
int n,m,mod;
struct Matrix{
int num[WR][WR];
Matrix(){memset(num,0,sizeof(num));}
Matrix operator*(const Matrix &b)const{
Matrix res;
for(int i=1;i<=n*2;i++){
for(int j=1;j<=n*2;j++){
for(int k=1;k<=n*2;k++){
res.num[i][j]=(res.num[i][j]+num[i][k]*b.num[k][j]%mod)%mod;
}
}
}
return res;
}
}mtx,ans;
int read(){
int s=0,w=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=(s<<1)+(s<<3)+ch-'0';
ch=getchar();
}
return s*w;
}
signed main(){
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
n=read();
for(int i=1;i<=n;i++){
char str[WR];
scanf("%s",str+1);
for(int j=1;j<=n;j++){
if(str[j]=='Y') mtx.num[i][j]=1;
else mtx.num[i][j]=0;
}
mtx.num[i][n+i]=1;
mtx.num[n+i][n+i]=1;
}
// for(int i=1;i<=n*2;i++){
// for(int j=1;j<=n*2;j++){
// printf("%lld ",mtx.num[i][j]);
// }
// printf("\n");
// }
m=read(),mod=read();
for(int i=1;i<=n*2;i++) ans.num[i][i]=1;
while(m){
if(m&1) ans=ans*mtx;
mtx=mtx*mtx;
m>>=1;
}
int res=0;
for(int i=1;i<=n;i++) res=(res+ans.num[i][n+i])%mod;
printf("%lld\n",res-n);
return 0;
}
本文来自博客园,作者:冬天丶的雨,转载请注明原文链接:https://www.cnblogs.com/WintersRain/p/16712023.html
为了一切不改变的理想,为了改变不理想的一切