• Educational Codeforces Round 60 Div. 2


      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!!!!!
    }
    

      场上什么傻逼题都写不出来,自闭了。

  • 相关阅读:
    9个数中取最大值最小值速度问题
    ubuntu 12.04安装git 1.8.11
    <转>Win7资源管理器更新后不断重启解决方案
    windows下安装安卓开发环境和NDK支持
    饱和算法
    bzip21.0.6
    《转》GetFileTitle与文件扩展名是否显示有关
    Ubuntu设置环境变量PATH的三种方法 <转>
    ubuntu下使用脚本交叉编译windows下使用的ffmpeg
    UnxUtils windows下linux命令
  • 原文地址:https://www.cnblogs.com/Gloid/p/10402778.html
Copyright © 2020-2023  润新知