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\n",ans+1);
}
return 0;
}
T3 天才绅士少女助手克里斯蒂娜
开方得:\(\sum\limits_{i=l}^{r-1} \sum\limits_{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]\)内枚举,即\(\sum\limits_{i=l}^r \sum\limits_{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倍
\(\sum\limits_{i=l}^r \sum\limits_{j=l}^r 2 x_i^2 y_j^2 - \sum\limits_{i=l}^r \sum\limits_{j=l}^r 2 x_i y_i x_j y_j\)
原式就是:
\(\sum\limits_{i=l}^r \sum\limits_{j=l}^r x_i^2 y_j^2 - \sum\limits_{i=l}^r \sum\limits_{j=l}^r x_i y_i x_j y_j\)
\((\sum\limits_{i=l}^{r}x_i^2)\times(\sum\limits_{i=l}^{r}y_i^2) - (\sum\limits_{i=l}^{r}x_iy_i)^2\)
用树状数组维护
\(\sum\limits_{i=l}^{r}x_i^2 和 \sum\limits_{i=l}^{r}y_i^2 和 \sum\limits_{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\n",f[n][ans]);
back(n,ans);
for(int i=top;i>=1;--i) printf("%d ",sta[i]);
return 0;
}