2019-11-5模拟测试

T1

在这里插入图片描述
思路:

  1. 判断御符能否被破除完
  2. ①可以:计算破除完御符后还能剩多少伤害值
    ②不行:直接计算不破御符时最大的伤害值

理由:贪心思想,因为只破除御符不会对伤害值有贡献,所以不可能存在破了一部分的情况。最优破除御符方案:使用刚好能破除当前御符的兵符,保证留下的伤害值更大。最优只破兵符方案:进攻方:降序排序。防守方:升序排序。使最大的进攻方兵符去打最小的防守方御符
代码实现:注意可能存在负数,处理一下即可
f l a g = 0 flag=0 能打完
f l a g ! = 0 flag!=0 不能打完

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+50;
int n,m1,m2,q[N];
long long ans=0;
struct node{int dat,num;}a[N],b[N],c[N],A[N],B[N],C[N];
bool cmp(const node &a,const node &b){return a.dat<b.dat;}
inline int read(){
	int cnt=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c^48);c=getchar();}
	return cnt*f;
}
ll Solve1(){ // 把御符打爆然后贪心打兵符 
	ll ans=0;
	bool flg=1;
	for(int i=1,j=1;i<=n;i++){
		while(j<=m1&&a[i].num&&a[i].dat>=b[j].dat){
			if(a[i].num<b[j].num){
				b[j].num-=a[i].num; 
				a[i].num=0;
				break;
			} a[i].num-=b[j].num;j++;
		} if(j>m1) {flg=0;break;}
	} 
	reverse(a+1,a+n+1);
	for(int i=1,j=1;i<=n;i++){
		if(!a[i].num) continue;
		while(j<=m2&&a[i].num&&a[i].dat>=c[j].dat&&c[j].dat<0){
			int num=min(a[i].num,c[j].num);
			a[i].num-=num;
			c[j].num-=num;
			ans+=1ll*num*(a[i].dat-c[j].dat);
			if(c[j].num==0)	++j; 
		} if(!flg) if(a[i].num&&a[i].dat>0) ans+=1ll*a[i].num*a[i].dat;
	} 
	return ans;
}
long long Solve2(){
	long long ans2=0;
	reverse(a+1,a+1+n);int j=1;
	for(register int i=1;i<=n;i++){//枚举当前 a中每一个兵符  
		while(j<=m2&&a[i].num&&a[i].dat>=c[j].dat){
			int now=min(a[i].num,c[j].num);
			ans2+=(long long)(a[i].dat-c[j].dat)*now;
			a[i].num-=now;c[j].num-=now;
			if(c[j].num==0)	j++;
		}
		if(j>m2)	break;
		if(a[i].dat<c[j].dat)	break;
	}
	return ans2;
}
int main(){
	n=read(),m1=read(),m2=read();
	for(register int i=1;i<=n;i++){A[i].dat=read(),A[i].num=read();}
	for(register int i=1;i<=m1;i++){B[i].dat=read(),B[i].num=read();}
	for(register int i=1;i<=m2;i++){C[i].dat=read(),C[i].num=read();}
	sort(A+1,A+1+n,cmp);sort(B+1,B+1+m1,cmp);sort(C+1,C+1+m2,cmp);
	memcpy(a,A,sizeof(A));
	memcpy(b,B,sizeof(B));
	memcpy(c,C,sizeof(C));
	ans=Solve1();
	//不能破除完,直接计算伤害  
	memcpy(a,A,sizeof(A));
	memcpy(b,B,sizeof(B));
	memcpy(c,C,sizeof(C));
	long long sum=Solve2();
	ans=max(ans,sum);
	printf("%lld",ans);
	return 0;
}

T2

在这里插入图片描述
f r o m   s o l u t i o n : from\ solution:
在这里插入图片描述
感谢高二hxy同学
代码:
f a w [ i ] [ j ] faw[i][j] 代表 i i 号点向上走 2 j 2^j 步的最大边权,就是倍增维护,跟LCA一样。
m a x max :维护向上边权的最大值,就是找到最小生成树上权值最大的那条边。
c n t 2 cnt2 是满足加入后 s u m w sumw 等于 X X 的边
c n t 3 cnt3 是加入后 s u m w sumw 大于 X X 的边
c n t 3 cnt3 在染色 c n t 2 cnt2 边的时候无论如何染色都不影响答案,所以 c n t 3 cnt3 随便选, c n t 2 cnt2 至少选一条
可以理解为是个 01 01 状态串,有 2 c n t 1 2^{cnt-1} 个数 0 01   11 11 (0……01~11……11)
s u m w = = X sumw==X 2 c n t 2 + n 1 2   >   ( c n t 2 + n 1 ) 2 2 m c n t 2 ( n 1 ) 2^{cnt2+n-1}-2\ ->\ (cnt2+n-1)是符合条件的边数,-2是有两条边颜色必须规定为不一样的;2^{m-cnt2-(n-1)}剩下的边可以任意选择
s u m w > X 2 ( 2 c n t 2 1 )   >   1 2 c n t 3 便 sumw>X:2*(2^{cnt2}-1) \ ->\ 本身已经符合条件,“-1”只有一条边需要规定颜色,“2*”颜色可以反过来染一次,剩余的cnt3条边可以随便染色

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
	ll x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=2e5+4,M=N*2;
const int mod=1e9+7;
inline ll ksm(ll a,ll b){
	ll ans=1%mod;
	while(b){
		if(b&1)	ans=(ll)ans*a%mod;
		a=a*a%mod;b>>=1;
	}
	return ans;
}
int cnt2,cnt3;
struct edge{int u,v;ll w;int nxt;};
struct tree{
	edge e[M];
	int fir[N],tot,faw[N][18],f[N][18],dep[N];
	inline void clear(){memset(fir,0,sizeof(fir));tot=0;}
	inline void add(int u,int v,int w){e[++tot]=(edge){u,v,w,fir[u]},fir[u]=tot;}
	void dfs(int u,int fa){
		for(int i=1;i<=17;i++){f[u][i]=faw[u][i]=0;}
		dep[u]=dep[fa]+1;
		for(int i=1;i<=17;i++){f[u][i]=f[f[u][i-1]][i-1];faw[u][i]=max(faw[u][i-1],faw[f[u][i-1]][i-1]);}
		for(int i=fir[u],v;i;i=e[i].nxt){
			v=e[i].v;if(v==fa)continue;
			faw[v][0]=e[i].w;f[v][0]=u;dfs(v,u);
		}
	}
	inline int lca(int x,int y){
		int ret=0;
		if(dep[x]<dep[y])swap(x,y);
		for(int i=17;i>=0;i--)if(dep[f[x][i]]>=dep[y]){ret=max(ret,faw[x][i]);x=f[x][i];}
		if(x==y)	return ret;
		for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i]){ret=max(ret,max(faw[x][i],faw[y][i]));x=f[x][i],y=f[y][i];}
		return max(ret,max(faw[x][0],faw[y][0]));
	}
}mst;
edge e[M];
int n,m,fa[N];ll X,sumw;
bool vis[M];
inline bool cmp(edge a,edge b){return a.w<b.w;}
inline void clear(){
	sumw=0;cnt2=cnt3=0;
	mst.clear();memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++){fa[i]=i;}
}
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int t;
int main(){
	t=read();
	while(t--){
		n=read(),m=read();X=read();clear();
		for(int i=1;i<=m;i++){e[i].u=read(),e[i].v=read(),e[i].w=read();}
		sort(e+1,e+m+1,cmp);int tot=0,tp,x,y;
		for(tp=1;tp<=m;tp++){
			x=e[tp].u,y=e[tp].v;
			if(find(x)!=find(y)){
				fa[find(x)]=find(y);vis[tp]=1;
				mst.add(x,y,e[tp].w);mst.add(y,x,e[tp].w);
				tot++;sumw+=e[tp].w;
				if(tot==n-1)break;
			}
		}
		mst.dfs(1,0);
		if(sumw==X){
			for(int i=2;i<=m;i++){
				if(vis[i])	continue;
				ll xx=sumw+e[i].w-mst.lca(e[i].u,e[i].v);
				if(xx==X)	cnt2++;
				if(xx>X)	cnt3++;
			}
			printf("%lld\n",(ksm(2,cnt2+n-1)-2+mod)%mod*ksm(2,m-cnt2-(n-1))%mod);
			continue;
		}
		for(int i=2;i<=m;i++){
			if(vis[i])	continue;
			ll xx=sumw+e[i].w-mst.lca(e[i].u,e[i].v);
			if(xx==X)cnt2++;
			if(xx>X)	cnt3++;
		}
		printf("%lld\n",(ksm(2,cnt2)-1+mod)*2%mod*ksm(2,cnt3)%mod);
	}
	return 0;
}

T3(数位DP+KMP/AC自动机)

在这里插入图片描述
在这里插入图片描述
(代码是标程的)
咕咕咕我把字符串和数位DP坑填了再重做这道题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
	ll x=0,w=1;char ch=0;
	while (ch<'0' || ch>'9'){ch=getchar();if (ch=='-') w=-1;}
	while (ch<='9' && ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*w;
}
namespace pb_ds{   
    namespace io{
        const int MaxBuff=1<<15;
        const int Output=1<<23;
        char B[MaxBuff],*S=B,*T=B;
		#define getc() ((S==T)&&(T=(S=B)+fread(B,1,MaxBuff,stdin),S==T)?0:*S++)
        char Out[Output],*iter=Out;
        inline void flush(){
            fwrite(Out,1,iter-Out,stdout);
            iter=Out;
        }
    }
    template<class Type> inline void Print(register Type x,register char ch='\n'){
        using namespace io;
        if(!x) *iter++='0';
        else{
            if(x<0) *iter++='-',x=-x;
            static int s[100]; 
            register int t=0;
            while(x) s[++t]=x%10,x/=10;
            while(t) *iter++='0'+s[t--];
        }
        *iter++=ch;
    }
}
using namespace pb_ds;
const int N=5e4+5;
const int M=21;
const int L=17;
const int Mod=1e9+7;
const ll inf=(ll)1e18+1;
int T,n,m,q;
bool p[N][10];
int fail[M],val[L][N][M],trans[M][10],pw[L]={10};
ll dp[N][M],rkl[L][N][M],rkr[L][N][M];
char str[M],s[N],ed[L][N][M];
inline ll fix(ll x){
	return x<inf?x:inf;
}
inline void KMP(){
	fail[0]=fail[1]=0;
	for (int i=2;i<=m;++i){
		int now=fail[i-1];
		while (now && str[now+1]!=str[i]) now=fail[now];
		if (str[now+1]==str[i]) fail[i]=now+1;
		else fail[i]=0;
	}
}
inline void init(){
	for (int i=0;i<m;++i){
		for (int j=0;j<=9;++j){
			int now=i;
			while (now && str[now+1]!=j+'0') now=fail[now];
			if (str[now+1]!=j+'0') trans[i][j]=0;
			else trans[i][j]=now+1;
		}
	}
	for (int j=0;j<=9;++j) trans[m][j]=m;
}
inline void input(){
	n=read(),q=read();
 	scanf("%s%s",str+1,s+1);
 	m=strlen(str+1);
 	for (int i=1;i<=n;++i){
 		if (s[i]=='?') memset(p[i],1,sizeof(p[i]));
 		else memset(p[i],0,sizeof(p[i])),p[i][s[i]-'0']=1;
 	}
 	KMP(),init();
}
inline int query(ll k){
	if (k>dp[1][0]) return -1;
	int x=1,y=0,res=0;
	while (x<=n){
		for (int i=L-1;~i;--i){
			if (x+(1<<i)<=n+1 && rkl[i][x][y]<k && k<=rkr[i][x][y]){
				res=(1ll*res*pw[i]+val[i][x][y])%Mod;
				k-=rkl[i][x][y],y=ed[i][x][y],x+=(1<<i);
			}
		}
		if (x>n) break;
		for (int i=0;i<=9;++i){
			if (k>dp[x+1][trans[y][i]]) k-=dp[x+1][trans[y][i]];
			else{
				res=(10ll*res+i)%Mod;
				++x,y=trans[y][i];
				break;
			}
		}
	}
	return res;
}
int main(){
	freopen("shuawang.in","r",stdin);
    freopen("shuawang.out","w",stdout);
 	for (int i=1;i<L;++i)
 		pw[i]=1ll*pw[i-1]*pw[i-1]%Mod;
 	T=read();
 	while (T--){
 		input();
 		for (int i=0;i<=m;++i) 
 			dp[n+1][i]=(i==m);
 		for (int i=n;i;--i){
 			for (int j=0;j<=m;++j){
 				dp[i][j]=0;
 				ll mx=-1;
 				int nxt=-1;
 				for (int k=0;k<=9;++k){
 					if (p[i][k]){
 						dp[i][j]=fix(dp[i][j]+dp[i+1][trans[j][k]]);
 						if (dp[i+1][trans[j][k]]>mx) nxt=k,mx=dp[i+1][trans[j][k]];
 					}
 				}
 				ed[0][i][j]=trans[j][nxt];
                val[0][i][j]=nxt,rkl[0][i][j]=0;
                for (int k=0;k<nxt;++k)
                	 if (p[i][k]) rkl[0][i][j]=fix(rkl[0][i][j]+dp[i+1][trans[j][k]]);
               	rkr[0][i][j]=fix(rkl[0][i][j]+dp[i+1][trans[j][nxt]]);
 			}
 		}
 		for (int k=1;k<L;++k){
 			int len=(1<<(k-1));
 			for (int i=1;i+(1<<k)<=n+1;++i){
 				for (int j=0;j<=m;++j){
					int x=ed[k-1][i][j];
					ed[k][i][j]=ed[k-1][i+len][x];
					val[k][i][j]=(1ll*val[k-1][i][j]*pw[k-1]+val[k-1][i+len][x])%Mod;
					rkl[k][i][j]=fix(rkl[k-1][i][j]+rkl[k-1][i+len][x]);
					rkr[k][i][j]=fix(rkl[k-1][i][j]+rkr[k-1][i+len][x]);
 				}
 			}
 		}
 		while (q--){
 			ll k=read();
 			Print(query(k));
 		}
 		io::flush();
 	}   
	return 0;
}
发布了37 篇原创文章 · 获赞 11 · 访问量 1931

猜你喜欢

转载自blog.csdn.net/weixin_42750325/article/details/102946722