3.7

E. Arena 2100

https://codeforces.com/problemset/problem/1606/E
题意见洛谷。
n,x<=500
题解:显然是一道dp,考虑状态:需要能够随转移变化的状态,而转移显然是生命值的变化和人数的变化,什么生命值最能表征当前状态?最大生命值。故令f[i][j]表示总人数为i,最大生命值为j时的可行方案数。
当j<=i-1时,显然下一步全死,故f[i][j]=ji-(j-1)i;
ELSE f[i][j]=∑(f[k][j-i+1]C(i,k)(i-1)^(i-k));(注意人是不同的)

代码:

#define int long long
using namespace std;
const int N=605,mod=998244353;
int f[N][N],fac[N],finv[N],c[605][605];
int qpow(int x,int y){
	int ans=1;
	while(y){
		if(y&1) ans=ans*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ans;
}
void init(){
	fac[0]=1;
	for(int i=1;i<=505;i++){
		fac[i]=fac[i-1]*i%mod;
	}
	for(int i=0;i<=505;i++){
		finv[i]=qpow(fac[i],mod-2);
	}
}
int mo(int x){
	x=x%mod;
	if(x<0) x+=mod;
	if(x>mod) x-=mod;
	return x;
}
int C(int n,int m){
	if(m==0) return 1;
	return fac[n]*finv[m]%mod*finv[n-m]%mod;
}
signed main(){
	int n,x;cin>>n>>x;
	init();
	for(int i=2;i<=n;i++){
		for(int j=1;j<=x;j++){
			if(j<=i-1) f[i][j]=((qpow(j,i)-qpow(j-1,i))%mod+mod)%mod;
			else{
				int& w=f[i][j];
				for(int k=1;k<=i;k++){
					w=(w+C(i,k)*f[k][j-i+1]%mod*qpow(i-1,i-k)%mod)%mod;
				}
			}
		}
	}
	int ans=0;
	for(int i=1;i<=x;i++){
		ans=(ans+f[n][i])%mod;
	}
	cout<<ans;
}

New Game Plus! 2200

https://www.luogu.com.cn/problem/CF1415E
题解:观察一波,好像一个dp,一看数据,好像不太行,考虑贪心,而根据数据猜测是一个nlogn解法,可能是用堆。
正经分析开始:其给的k个归零操作实质上是把其分为k+1个组,贪心地,每个组元素不增。当放入一个元素时,获取该组当前地值f[i],f[i]->f[i]+a[k],易知用最大的那一组是最优的,故将组放入堆中,每次取top即可。
代码:

#define int long long
using namespace std;
const int N=5e5+100,INF=1e18;
int n,k;
int a[N],b[N],c[N],cnt[N];
priority_queue<int> q;
signed main(){
	cin>>n>>k;
	int w=n+1,tot=0,ans=0;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++) b[i]=a[n-i+1];
	for(int i=1;i<=k+1;i++) q.push(0);
	for(int i=1;i<=n;i++){
		int x=q.top();q.pop();
		ans+=x;
		q.push(x+b[i]);
	}
	cout<<ans;
}

Present 2100

https://www.luogu.com.cn/problem/CF1322B
题解:对于异或我们可以按位处理。难点在于如何处理进位,我们发现,对于第k位,只有前k位对其值有影响,我们可以将每一个数取模至前k位,对于任意两数x,y,相加后第k位为1当且仅当2k<=x+y<2(k+1)||2k+2^(k+1)<=x+y,故我们可以对取模过的数排序后倒序枚举,用双指针找到有多少个1,即可确定该位为0还是1,算法复杂度为O(nlognlogN).
代码:

#define int long long
using namespace std;
const int N=4e5+100,INF=1e18;
int n;
int a[N],b[N];
int tp(int x,int y){
	int l=1,r=1,ans=0;
	for(int i=n;i>=1;i--){
		while(l<=n&&b[l]+b[i]<x) l++;
		while(r<=n&&b[r]+b[i]<y) r++;
		if(l>n) break;
		if(r>n) r--,ans++;
		int ww=(l<=i&&r>i);
		ans+=(r-l)-ww;
	}
	return ans/2;
}
signed main(){
	cin>>n;
	int res=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	int k=25;
	for(int p=0;p<=k;p++){
		int q=(1<<p),w=(1<<(p+1)),e=((1<<(p+1))+(1<<p));
		for(int i=1;i<=n;i++) b[i]=a[i]%w;
		sort(b+1,b+n+1);
		int ans=tp(q,w)+tp(e,(1<<(p+2))-1);
		if(ans%2) res+=(1<<p);
	}
	cout<<res;
}

Missing Numbers 1900

https://www.luogu.com.cn/problem/CF1081E
题解:贪心地想,想要使得前2i项和为平方数, 由于x[2i]给定,故我们希望前2i-1项和尽量小.对于2i项,x[2i]=AA-BB=(A-B)(A+B)<=2e5,故我们可以O(sqrt(n))得到A和B的可能值,故我们可以O(nsqrt(n))得到可能的解。
代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+100;
int a[N],s[N];
signed main(){
	int n;cin>>n;
	for(int i=1;i<=n/2;i++){
		cin>>a[i*2];
	}
	for(int i=2;i<=n;i+=2){
		int x=a[i];
		for(int j=1;j*j<=x;j++){
			if(x%j!=0) continue;
			int u,v;
			u=(j+x/j)/2,v=(x/j-j)/2;
			if((j+x/j)%2||(x/j-j)%2) continue;
			if(v*v<=s[i-2]) continue;
			a[i-1]=v*v-s[i-2];
			s[i]=s[i-2]+a[i-1]+a[i];
		}
		if(!a[i-1]){
			cout<<"No";return 0;
		}
	}
	cout<<"Yes"<<endl;
	for(int i=1;i<=n;i++) cout<<a[i]<<" ";
}
posted @ 2023-03-07 22:34  wrong,anser  阅读(38)  评论(0)    收藏  举报