理由:贪心思想,因为只破除御符不会对伤害值有贡献,所以不可能存在破了一部分的情况。最优破除御符方案:使用刚好能破除当前御符的兵符,保证留下的伤害值更大。最优只破兵符方案:进攻方:降序排序。防守方:升序排序。使最大的进攻方兵符去打最小的防守方御符
代码实现:注意可能存在负数,处理一下即可
f l a g = 0 flag=0 flag=0 能打完
f l a g ! = 0 flag!=0 flag!=0 不能打完
#include
#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;
}
f r o m s o l u t i o n : from\ solution: from solution:
感谢高二hxy同学
代码:
f a w [ i ] [ j ] faw[i][j] faw[i][j]代表 i i i号点向上走 2 j 2^j 2j步的最大边权,就是倍增维护,跟LCA一样。
取 m a x max max:维护向上边权的最大值,就是找到最小生成树上权值最大的那条边。
c n t 2 cnt2 cnt2是满足加入后 s u m w sumw sumw等于 X X X的边
c n t 3 cnt3 cnt3是加入后 s u m w sumw sumw大于 X X X的边
c n t 3 cnt3 cnt3在染色 c n t 2 cnt2 cnt2边的时候无论如何染色都不影响答案,所以 c n t 3 cnt3 cnt3随便选, c n t 2 cnt2 cnt2至少选一条
可以理解为是个 01 01 01状态串,有 2 c n t − 1 2^{cnt-1} 2cnt−1个数 ( 0 … … 01 11 … … 11 ) (0……01~11……11) (0……01 11……11)
s u m w = = X sumw==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)}剩下的边可以任意选择 2cnt2+n−1−2 −> (cnt2+n−1)是符合条件的边数,−2是有两条边颜色必须规定为不一样的;2m−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条边可以随便染色 sumw>X:2∗(2cnt2−1) −> 本身已经符合条件,“−1”只有一条边需要规定颜色,“2∗”颜色可以反过来染一次,剩余的cnt3条边可以随便染色
#include
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;
}
(代码是标程的)
咕咕咕我把字符串和数位DP坑填了再重做这道题
#include
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;
}