2021 10.4 模拟测试

T1
贪心
主要有两种策略,第一种就是全打攻击符,第二种是在可以清除全部防御符打攻击符,但是要注意有一个小细节就是可能有负数,这时候对于第二种情况是减去负数是明显优于直接造成伤害的,所以要先扫一遍把负数情况计算好后再总体计算
#include<bits/stdc++.h>
#define ll long long
#define in read()
using namespace std;
inline int read()
{
int data=0,w=1; char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data*w;
}
inline void write(ll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=1e6+10;
const int M=205;
int n,m1,m2;
ll tmp[M*2];
struct node{int val;ll cnt;}a[N],b[N],c[N],aa[N],cc[N];
int cnt1,cnt2,cnt3;
int main()
{
// freopen("panwang3.in","r",stdin);
// freopen("panwang.out","w",stdout);
n=in,m1=in,m2=in;
for(int i=1;i<=n;i++) {int v=in,c=in;tmp[v+M]+=c;}
for(int i=0;i<M*2;i++)
if(tmp[i]) a[++cnt1].val=i-M,a[cnt1].cnt=tmp[i];
memset(tmp,0,sizeof(tmp));
for(int i=1;i<=m1;i++) {int v=in,c=in;tmp[v+M]+=c;}
for(int i=0;i<M*2;i++)
if(tmp[i]) b[++cnt2].val=i-M,b[cnt2].cnt=tmp[i];
memset(tmp,0,sizeof(tmp));
for(int i=1;i<=m2;i++) {int v=in,c=in;tmp[v+M]+=c;}
for(int i=0;i<M*2;i++)
if(tmp[i]) c[++cnt3].val=i-M,c[cnt3].cnt=tmp[i];
int flag=1;ll ans=0;
for(int i=1;i<=cnt1;i++) aa[i]=a[i];
for(int i=1;i<=cnt3;i++) cc[i]=c[i];
// cout<<cnt1<<' '<<cnt2<<' '<<cnt3<<'\n';
for(int i=1,j=1;i<=cnt2;i++)
{
while(j<cnt1&&a[j].val<b[i].val) ++j;
if(j==cnt1&&a[j].val<b[i].val) {flag=0;break;}
if(a[j].cnt>b[i].cnt) a[j].cnt-=b[i].cnt;
else b[i].cnt-=a[j].cnt,a[j].cnt=0,++j,--i;
}
if(flag)
{
for(int i=1,j=cnt1;j&&i<=cnt3;i++)
{
if(c[i].val>=0) break;
if(!a[j].cnt) continue;
if(a[j].val<=c[i].val) break;
if(a[j].cnt>c[i].cnt)
{
a[j].cnt-=c[i].cnt;
ans+=c[i].cnt*(a[j].val-c[i].val);
}
else
{
c[i].cnt-=a[j].cnt;
ans+=a[j].cnt*(a[j].val-c[i].val);
a[j].cnt=0,--j,--i;
}
}
for(int i=1;i<=cnt1;i++)
if(a[i].val>0) ans+=a[i].cnt*a[i].val;
}
ll anss=0;
for(int i=1,j=cnt1;j&&i<=cnt3;i++)
{
if(aa[j].val<=cc[i].val) break;
if(aa[j].cnt>cc[i].cnt)
{
aa[j].cnt-=cc[i].cnt;
anss+=cc[i].cnt*(aa[j].val-cc[i].val);
}
else
{
cc[i].cnt-=aa[j].cnt;
anss+=aa[j].cnt*(aa[j].val-cc[i].val);
aa[j].cnt=0,--j,--i;
}
}
cout<<ans<<' '<<anss<<'\n';
ans=max(ans,anss);
write(ans);
}
T2
现将原数组去重,记录每个数出现的次数,然后分类讨论,分别对于出现一次,二次,三次讨论统计答案,答案初始化为总答案减去不合法方案即可,但需要卡下常
#include<bits/stdc++.h>
#define re register
using namespace std;
namespace Fastio{
namespace Fread{
const int SIZE=(1<<21);
char buf[SIZE],*S,*T;
inline char getchar(){
if(S==T){
T=(S=buf)+fread(buf,1,SIZE,stdin);
if(S==T) return '\n';
}
return *S++;
}
}
namespace Fwrite{
const int SIZE=(1<<21);
char buf[SIZE],*S=buf,*T=buf+SIZE;
inline void flush(){fwrite(buf,1,S-buf,stdout);S=buf;}
inline void putchar(register char c){*S++=c;if(S==T) flush();}
struct NTR{~NTR(){flush();}}ztr;
}
#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endif
struct Reader{
template<typename T>
Reader &operator>>(register T&x){
register char c=getchar();
register T dp=1;
while(c<'0'||c>'9'){if(c=='-') dp=-1;c=getchar();}
x=0;
while(c>='0'&&c<='9') x=x*10+(c-'0'),c=getchar();
x*=dp;
return *this;
}
Reader &operator>>(register char &c){
c=getchar();
while(c==' '||c=='\n') c=getchar();
return *this;
}
Reader &operator>>(register char *str){
register int len=0;
register char c=getchar();
while(c==' '||c=='\n') c=getchar();
while(c!=' '&&c!='\n'&&c!='\r') str[len++]=c,c=getchar();
str[len]='\0';
return *this;
}
inline Reader(){}
}cin;
const char endl='\n';
struct Writer{
template<typename T>
Writer &operator<<(T x){
if(!x){putchar('0');return *this;}
if(x<0) putchar('-'),x=-x;
static int sta[111];
register int top=0;
while(x) sta[++top]=x%10,x/=10;
while(top) putchar(sta[top]+'0'),--top;
return *this;
}
Writer &operator<<(register char c){putchar(c);return *this;}
Writer &operator<<(register char *str){register int cur=0;while(str[cur]) putchar(str[cur++]);return *this;}
Writer &operator<<(register const char *str){register int cur=0;while(str[cur]) putchar(str[cur++]);return *this;}
inline Writer(){}
}cout;
#define cin Fastio::cin
#define cout Fastio::cout
#define endl Fastio::endl
}
using namespace Fastio;
const int N=2400;
unordered_map<int,int>mp;
int n,mod;
int a[N],ans,b[N],num[N],cnt;
int f[N][N];
inline int mul(int a,int b){return 1ll*a*b%mod;}
int qpow(int x,int y)
{
int ret=1;
while(y)
{
if(y&1) ret=mul(ret,x);
x=mul(x,x);
y>>=1;
}
return ret;
}
void pre()
{
for(re int i=1;i<=cnt;i++)
for(re int j=i;j<=cnt;j++)
f[j][i]=f[i][j]=mul(b[i],b[j]);
}
int main()
{
// freopen("awesome.in","r",stdin);
// freopen("awesome.out","w",stdout);
cin>>n>>mod;
for(re int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
for(re int i=1;i<=n;i++)
{
int r=i;
while(a[r+1]==a[i]) ++r;
b[++cnt]=a[i];num[cnt]=r-i+1;
if(num[cnt]>=2) ++mp[mul(b[cnt],b[cnt])];
i=r;
}
pre();
for(re int i=1;i<=cnt;i++)
for(re int j=i+1;j<=cnt;j++)
mp[f[i][j]]++;
for(re int i=1;i<=cnt;i++)
{
if(num[i]==2) mp[f[i][i]]--;
if(num[i]==1)
for(re int j=i+1;j<=cnt;j++) mp[f[i][j]]--;
ans+=mp[qpow(b[i],mod-2)];
if(num[i]>=3) mp[f[i][i]]--;
if(num[i]>=2)
for(re int j=i+1;j<=cnt;j++) mp[f[i][j]]--;
}
cout<<ans;
}
T3
对于一条长度为\(l\) 的链,贪心地,我们发现用容量最大的\(l\) 个背包一定是最优的背包安排。
因此将所有点按\(x\) 降序排序,并依次枚举所有点,用权值树状数组维护每个\(y\) 坐标结尾的最长链长度,注意需要维护能够存的下当前点背包数量,并在更新树状数组时将更新的答案与这个值取 \(min\)
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mp make_pair
#define lowbit(x) (x&(-x))
#define in read()
using namespace std;
inline int read()
{
int data=0,w=1; char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data*w;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=1e5+10;
int T,n,m;
int c[N],bag[N];
pii a[N],tmp[N];
inline int query(int p){int ret=0;for(;p;p-=lowbit(p)) ret=max(ret,c[p]);return ret;}
inline void update(int p,int v){for(;p<=n;p+=lowbit(p)) c[p]=max(c[p],v);}
void work()
{
n=in;
for(int i=1,w,v;i<=n;++i) w=in,v=in,a[i]=mp(w,v);
sort(a+1,a+n+1);
for(int i=1;i<=n;++i) tmp[i]=mp(a[i].second,i);
sort(tmp+1,tmp+1+n,greater<pii>());
for(int i=1,j=0;i<=n;++i)
{
if(i==1||tmp[i].first!=tmp[i-1].first)++j;
a[tmp[i].second].second=j;
}
m=in;
for(int i=1;i<=m;++i) bag[i]=in;
sort(bag+1,bag+m+1,greater<int>());
memset(c,0,sizeof(c));
int ans=0;
for(int i=n,j=0;i;--i)
{
while(j<m&&bag[j+1]>=a[i].first) ++j;
int now=min(query(a[i].second)+1,j);
update(a[i].second,now);
ans=max(ans,now);
}
write(ans),putchar('\n');
}
int main()
{
//freopen("soc.in","r",stdin);
T=in;
while(T--) work();
return 0;
}
/*
2
4
1 200
2 300
5 400
3 100
4
1 10 5 1
4
1 200
2 300
5 400
10 500
5
1 2 3 4 5
*/
T4
设\(dp[i][d]\) 表示\(i\) 个节点深度不超过\(d\) 的有根树数目(很显然,若计算出所有 \(dp[i][d]\),则可以通过差分求得各答案)。若不考虑禁手,则可以枚举根为编号次大子树的大小 ,并进行转移,具体转移方程为:
\[dp[i][d]=\displaystyle\sum^{i-1}_{j=1}dp[i-j][d]\times dp[j][d-1]\times \binom {i-2 }{j-1}
\]
对于禁手,我们只需要在转移时将对应的\(dp[j][d-1]\) 看作\(0\) 即可。
#include<bits/stdc++.h>
#define in read()
using namespace std;
inline int read()
{
int data=0,w=1; char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data*w;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int mod=998244353;
const int N=510;
int add(int a,int b){return (a+=b)>=mod?a-=mod:a;}
int mul(int a,int b){return 1ll*a*b%mod;}
int c[N][N],f[N][N],ban[N];
int main()
{
// freopen("soc.in","r",stdin);
int n,k;n=in,k=in;
for(int i=0;i<=n;++i)
{
c[i][0]=1;
for(int j=1;j<=i;++j)c[i][j]=add(c[i-1][j-1],c[i-1][j]);
}
for(int i=1,x;i<=k;++i)x=in,ban[x]=1;
f[1][1]=ban[1]?0:1;
for(int d=2;d<=n;++d)
{
for(int i=1;i<=n;++i)
{
if(i==1){f[i][d]=1;continue;}
for(int j=1;j<i;++j)f[i][d]=add(f[i][d],mul(mul(f[i-j][d],f[j][d-1]),c[i-2][j-1]));
}
for(int i=1;i<=n;++i)if(ban[i])f[i][d]=0;
}
int L,R;cin>>L>>R;
for(int i=L;i<=R;++i) write((f[n][i]-f[n][i-1]+mod)%mod),putchar(' ');
return 0;
}

浙公网安备 33010602011771号