zoukankan      html  css  js  c++  java
  • 省选测试21

    A. Skip

    分析

    (f[i]) 为上一次参加的比赛是第 (i) 场的最大愉悦值

    (f[i]=max(f[i],f[j]-frac{(i-j)(i-j-1)}{2}+a[i]),j<i,a[j] leq a[i])

    对于随机的数据,把枚举的范围卡到 (3000) 即可

    容易发现,如果没有 (a[j] leq a[i]) 的限制,那么就是一个裸的斜率优化 (dp)

    (f[i]-frac{i^2}{2}-frac{i}{2}) 看做 (y),把 (i) 看做 (x),把 (-i) 看做 (k)

    横坐标和斜率都是单调的

    加上后面的限制之后可以用 (CDQ) 分治人为地排出权值的单调性

    具体地,在大区间内按照权值从小到大排序,在计算左区间对右区间的贡献时按照在原数组中的下标排序

    代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e5+5;
    const double eps=1e-8;
    int a[maxn],n,id[maxn];
    long long f[maxn];
    bool cmp1(rg int aa,rg int bb){
    	if(a[aa]==a[bb]) return aa<bb;
    	return a[aa]<a[bb];
    }
    bool cmp2(rg int aa,rg int bb){
    	return aa<bb;
    }
    double getY(rg int id){
    	return 1.0*f[id]-0.5*id*id-0.5*id;
    }
    double getX(rg int id){
    	return 1.0*id;
    }
    double getxl(rg int i,rg int j){
    	if(std::abs(getX(j)-getX(i))<eps){
    		if(std::abs(getY(j)-getY(i))<eps) return 0;
    		else if(getY(j)>getY(i)) return 1e18;
    		else return -1e18;
    	}
    	return (getY(j)-getY(i))/(getX(j)-getX(i));
    }
    int q[maxn],head,tail;
    void solve(rg int l,rg int r){
    	if(l==r) return;
    	rg int mids=(l+r)>>1;
    	solve(l,mids);
    	std::sort(id+l,id+mids+1,cmp2);
    	std::sort(id+mids+1,id+r+1,cmp2);
    	head=1,tail=0;
    	rg int now=l;
    	for(rg int i=mids+1;i<=r;i++){
    		while(id[now]<id[i] && now<=mids){
    			while(head<tail && getxl(q[tail],id[now])>=getxl(q[tail-1],q[tail])) tail--;
    			q[++tail]=id[now];
    			now++;
    		}
    		while(head<tail && getxl(q[head],q[head+1])>=-1.0*id[i]) head++;
    		if(head<=tail) f[id[i]]=std::max(f[id[i]],f[q[head]]-1LL*(id[i]-q[head]-1)*(id[i]-q[head])/2LL+a[id[i]]);
    	}
    	std::sort(id+l,id+r+1,cmp1);
    	solve(mids+1,r);
    }
    int main(){
    	n=read();
    	for(rg int i=1;i<=n;i++) a[i]=read(),id[i]=i;
    	memset(f,~0x3f,sizeof(f));
    	f[0]=0,a[0]=-0x3f3f3f3f;
    	std::sort(id,id+n+1,cmp1);
    	solve(0,n);
    	rg long long ans=-0x3f3f3f3f3f3f3f3f;
    	for(rg int i=0;i<=n;i++) ans=std::max(ans,f[i]-1LL*(n-i)*(n-i+1)/2LL);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    B. String

    分析

    考虑搜索,搜索时从小到大去加字符相当于按照字典序排序

    搜索的时候记录一个字符出现次数的前缀和来判断是否合法

    数据范围比较大,要记忆化

    因为影响答案的只是上一个字符出现的次数和前面已经出现了 (1 sim k) 次的字符有多少种

    把后面的部分哈希一下存到以前面部分为下标的 (map) 中即可

    这样写 (k>8) 的也能直接搜过,不用特判

    代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<unordered_map>
    #define rg register
    typedef unsigned long long ull;
    typedef long long ll;
    const int maxn=1e6+5;
    const ull bas=233333;
    int k,tax[maxn],tot,vis[maxn],cnt;
    char s[maxn];
    ull ed;
    ll n;
    std::unordered_map<ull,ll> mp[30];
    ll dfs(rg ull zt,rg int lat,rg ll rk){
    	if(mp[lat].find(zt)!=mp[lat].end() && rk>mp[lat][zt]) return mp[lat][zt];
    	if(zt==ed){
    		if(rk==1){
    			printf("%s
    ",s+1);
    			std::exit(0);
    		} else {
    			return mp[lat][zt]=1;
    		}
    	}
    	rg ll nans=0,tmp=0;
    	cnt++;
    	for(rg int i=0;i<26;i++){
    		if(i+'a'==s[cnt-1]) continue;
    		vis[i]++,tax[vis[i]]++;
    		rg ull nzt=0;
    		for(rg int j=1;j<=k;j++) nzt=nzt*bas+j*tax[j];
    		if(tax[vis[i]]<=k-vis[i]+1){
    			s[cnt]='a'+i;
    			tmp=dfs(nzt,vis[i],rk);
    			nans+=tmp,rk-=tmp;
    		}
    		tax[vis[i]]--,vis[i]--;
    	}
    	cnt--;
    	return mp[lat][zt]=nans;
    }
    int main(){
    	scanf("%d%lld",&k,&n);
    	for(rg int i=1;i<=k;i++) ed=ed*bas+i*(k-i+1);
    	dfs(0,0,n);
    	printf("-1
    ");
    	return 0;
    }
    

    C. Permutation

    分析

    (f[i][j]=f[i-1][j]+f[i][j-1]+j,f[1][x]=x+1,f[x][0]=1)

    那么答案就是 (f[m][n-k-1])

    发现可以用组合数的含义去优化

    然后再用 (sumlimits_{i=a}^{b} C_i^y = C_{b+1}^{y+1} -C_a^{y+1}) 就可以做到线性

    代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e6+5,mod=1e9+7;
    inline int addmod(rg int now1,rg int now2){
    	return now1+=now2,now1>=mod?now1-mod:now1;
    }
    inline int delmod(rg int now1,rg int now2){
    	return now1-=now2,now1<0?now1+mod:now1;
    }
    inline int mulmod(rg long long now1,rg int now2){
    	return now1*=now2,now1>=mod?now1%mod:now1;
    }
    int n,k,m,jc[maxn],jcc[maxn],ny[maxn];
    int getC(rg int nn,rg int mm){
    	return mulmod(jc[nn],mulmod(jcc[mm],jcc[nn-mm]));
    }
    int ans=0;
    int main(){
    	n=read(),k=read(),m=read();
    	n-=(k+1);
    	ny[1]=1;
    	for(rg int i=2;i<maxn;i++) ny[i]=mulmod(mod-mod/i,ny[mod%i]);
    	jc[0]=jcc[0]=1;
    	for(rg int i=1;i<maxn;i++) jc[i]=mulmod(jc[i-1],i),jcc[i]=mulmod(jcc[i-1],ny[i]);
    	if(m>=2) for(rg int j=0;j<=n;j++) ans=addmod(ans,mulmod(n-j,getC(m-1+j,j+1)));
    	for(rg int j=0;j<=n;j++) ans=addmod(ans,getC(m+j-1,m-1));
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Eclipse/MyEclipse 选择Android NDK目录时提示“Not a valid NDK directory”
    Eclipse更改颜色主题
    Android模拟器访问本机服务器
    DIV水平垂直居中的CSS兼容写法
    Python3中使用PyMySQL连接Mysql
    Windows7 IE11 F12控制台DOC资源管理器报错的问题解决方法
    Windows 7无法卸载及安装IE11的解决方法
    查看端口占用
    VS2010/VS2013中ashx代码折叠的问题
    手机页面关于头部固定定位与input出现的问题
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14407419.html
Copyright © 2011-2022 走看看