2020-10-13 联赛模拟测试15

T1游戏

把每个武器的两个属性连上边,即将武器看作边,将属性看做点。
对于树联通块,显然不选最大的节点(属性)。
对于非树联通块,因为每个武器可以选两个相邻节点之一,显然每个节点(属性)都可以被选。

T2嘟嘟噜

n个人,每次报到m的死
初始ans = 0, 枚举 2 <= i <= n, 每次 (ans+=m)%=i;
最后 ans + 1 即答案
本题n达到了1e9显然O(n)不可过,于是考虑优化
n 很大, m 相对较小
对于每次取模,发现,当i很大时,取模很可能没用上,所以可以将加法转化为乘法

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int n,m,ans,siz;
int main(){
	freopen("mayuri.in","r",stdin);
	freopen("mayuri.out","w",stdout);
	int t;scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		ans=0;
		for(int i=2;i<=n;i+=siz){
			siz=max(1,min(n-i+1,(i-ans)/m));
			(ans+=m*siz)%=(i+siz-1);
		}
		printf("%d
",ans+1);
	}
	return 0;
}

T3 天才绅士少女助手克里斯蒂娜

开方得:(sumlimits_{i=l}^{r-1} sumlimits_{j=i+1}^r x_i^2 y_j^2 x_j^2 y_i^2 -2*x_i y_i x_j y_j)
发现如果 将(i,j)都在([l,r])内枚举,即(sumlimits_{i=l}^r sumlimits_{j=l}^r x_i^2 y_j^2 + x_j^2 y_i^2 - 2 x_i y_i x_j y_j)
恰好为原式2倍
(sumlimits_{i=l}^r sumlimits_{j=l}^r 2 x_i^2 y_j^2 - sumlimits_{i=l}^r sumlimits_{j=l}^r 2 x_i y_i x_j y_j)
原式就是:
(sumlimits_{i=l}^r sumlimits_{j=l}^r x_i^2 y_j^2 - sumlimits_{i=l}^r sumlimits_{j=l}^r x_i y_i x_j y_j)
((sumlimits_{i=l}^{r}x_i^2) imes(sumlimits_{i=l}^{r}y_i^2) - (sumlimits_{i=l}^{r}x_iy_i)^2)
用树状数组维护
(sumlimits_{i=l}^{r}x_i^2 和 sumlimits_{i=l}^{r}y_i^2 和 sumlimits_{i=l}^{r} x_i*y_i) 即可
每次单点修改,区间查询

T4凤凰院凶真((LCIS)

最长公共上升子序列 , (f[i][j])表示对于(a[])的前(i)个,(b[])的前(j)个,且以(b[j])结尾的最大长度
(a[i]!=b[j] : f[i][j]=f[i-1][j];)
(a[i]==b[j] : f[i][j]=f[i-1][k]+1 (0<=k<j))
(O(n^3))
考虑优化:
可以发现枚举(k)(a[i])是不变的,只要(b[j]==a[i]),(f[i][j])就会被前面的最优决策点+1更新
那么我们只需要在枚举j的时候顺便更新一个最优决策点即可避免枚举k
复杂度 (O(n^2))
注意记录来源回溯的时候,不能用一维数组,要用二维数组记录上一个选什么,否则你会看到十分神奇的结果

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=5e3+5;
int n,a[maxn];
int m,b[maxn];
int f[maxn][maxn];
int fr[maxn][maxn];
int sta[maxn],top;
int ans;
void back(int i,int j){
	if(!i||!j) return;
	if(fr[i][j]!=j) sta[++top]=b[j];
	back(i-1,fr[i][j]);
}
int main(){
	freopen("phoenix.in","r",stdin);
	freopen("phoenix.out","w",stdout);
	scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	scanf("%d",&m); for(int i=1;i<=m;++i) scanf("%d",&b[i]);
	for(int i=1;i<=n;++i){
		int val=f[i-1][0],pos=0;
		for(int j=1;j<=m;++j){
			if(a[i]!=b[j]){
				f[i][j]=f[i-1][j];
				fr[i][j]=j;
			}
			else{
				f[i][j]=val+1;
				fr[i][j]=pos;
			}
			if(b[j]<a[i]&&f[i-1][j]>val){
				val=f[i-1][j];
				pos=j;
			}
		}
	}
	int ans=0;
	for(int i=1;i<=m;++i) if(f[n][i]>f[n][ans]) ans=i;
	printf("%d
",f[n][ans]);
	back(n,ans);
	for(int i=top;i>=1;--i) printf("%d ",sta[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/Lour688/p/13809399.html