2021 10.4 模拟测试

image

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;
}
posted @ 2021-10-05 22:50  Socratize  阅读(47)  评论(0)    收藏  举报