F:考虑对于每个字母对求出删掉哪些字符集会造成字符串不合法,只要考虑相邻出现的该字母对即可,显然这可以在O(np2)(或小常数O(np3))内求出。然后再对每个字符集判断是否能通过一步删除转移而来即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 100010 #define M 17 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,c[N],b[N],cnt[M],ans; char s[N]; bool a[M][M],f[1<<M],g[1<<M]; signed main() { #ifndef ONLINE_JUDGE freopen("f.in","r",stdin); freopen("f.out","w",stdout); const char LL[]="%I64d "; #endif n=read(),m=read(); scanf("%s",s+1);for (int i=1;i<=n;i++) cnt[c[i]=s[i]-'a']++; for (int i=0;i<m;i++) for (int j=0;j<m;j++) { a[i][j]=read(); if (i<=j&&!a[i][j]) { memset(g,0,sizeof(g));int last=-1,s=0; for (int x=1;x<=n;x++) { if (c[x]==i||c[x]==j) { if (last==i+j-c[x]) g[s]=1; last=c[x];s=0; } else s|=(1<<c[x]); } for (int x=1;x<(1<<m);x++) if (!g[x]&&!(x&(1<<i))&&!(x&(1<<j))) { for (int t=x,y=t&-t;t;t^=y,y=t&-t) g[x]|=g[x^y]; } for (int x=0;x<(1<<m);x++) f[x]|=g[x]; } } ans=n; for (int i=1;i<(1<<m);i++) { if (!f[i]) { f[i]=1; for (int j=0;j<m;j++) if ((i&(1<<j))&&!f[i^(1<<j)]) {f[i]=0;break;} } if (!f[i]) { int tot=n; for (int j=0;j<m;j++) if (i&(1<<j)) tot-=cnt[j]; ans=min(ans,tot); } } cout<<ans; return 0; //NOTICE LONG LONG!!!!! }
G:考虑一个数被删掉对一个区间产生的贡献,只考虑某一侧,显然如果该区间内该数为最大值,贡献即为该侧区间长度,否则为其到下一个比他大的数的距离。离线后扫过去维护贡献,线段树实现区间加一次函数即可。又卡我常!
#include<cstdio> #include<iostream> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 1000010 #define tree lazy char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N],nxt[N],L[N<<2],R[N<<2]; ll ans[N],lazy[N<<2][2]; struct data{int l,r,i;ll ans; }q[N]; bool cmp(const data&a,const data&b) { return a.l<b.l; } void build(int k,int l,int r) { L[k]=l,R[k]=r;lazy[k][0]=lazy[k][1]=0; if (l==r) return; int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void down(int k) { tree[k<<1][0]+=tree[k][0],tree[k<<1|1][0]+=tree[k][0],tree[k][0]=0; tree[k<<1][1]+=tree[k][1],tree[k<<1|1][1]+=tree[k][1],tree[k][1]=0; } ll query(int k,int p) { if (L[k]==R[k]) return 1ll*lazy[k][1]*p+lazy[k][0]; down(k); int mid=L[k]+R[k]>>1; if (p<=mid) return query(k<<1,p); else return query(k<<1|1,p); } void add(int k,int l,int r,int u,int x) { if (L[k]==l&&R[k]==r) {lazy[k][1]++;lazy[k][0]+=x;return;} down(k); int mid=L[k]+R[k]>>1; if (r<=mid) add(k<<1,l,r,u,x); else if (l>mid) add(k<<1|1,l,r,u,x); else add(k<<1,l,mid,u,x),add(k<<1|1,mid+1,r,u,x); } void add(int k,int l,int r,int x) { if (L[k]==l&&R[k]==r) {lazy[k][0]+=x;return;} down(k); int mid=L[k]+R[k]>>1; if (r<=mid) add(k<<1,l,r,x); else if (l>mid) add(k<<1|1,l,r,x); else add(k<<1,l,mid,x),add(k<<1|1,mid+1,r,x); } void solve() { nxt[n+1]=n+1; for (int i=n;i>=1;i--) { int j=i+1; while (a[j]<a[i]) j=nxt[j]; nxt[i]=j; } build(1,1,n); sort(q+1,q+m+1,cmp); int cur=0; for (int i=1;i<=n;i++) { while (q[cur+1].l==i) cur++,q[cur].ans-=query(1,q[cur].r); add(1,i,nxt[i]-1,1,-i); if (nxt[i]<=n) add(1,nxt[i],n,nxt[i]-i-1); } for (int i=1;i<=m;i++) q[i].ans+=query(1,q[i].r); } signed main() { #ifndef ONLINE_JUDGE freopen("g.in","r",stdin); freopen("g.out","w",stdout); #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); a[0]=a[n+1]=n+1; for (int i=1;i<=m;i++) q[i].l=read(); for (int i=1;i<=m;i++) q[i].r=read(); for (int i=1;i<=m;i++) q[i].i=i; solve(); reverse(a+1,a+n+1);for (int i=1;i<=m;i++) q[i].l=n-q[i].l+1,q[i].r=n-q[i].r+1,swap(q[i].l,q[i].r); solve(); for (int i=1;i<=m;i++) q[i].ans+=q[i].r-q[i].l+1; for (int i=1;i<=m;i++) ans[q[i].i]=q[i].ans; for (int i=1;i<=m;i++) printf("%I64d ",ans[i]); return 0; //NOTICE LONG LONG!!!!! }
场上什么傻逼题都写不出来,自闭了。