今天最后一场个人赛 出题玩抽象的 密码是 l a s t d a n c e lastdance lastdance 然后题名连起来是个人赛的最后一舞
最抽象的我觉得还是一套题出三道大模拟,人写没了
寻思最后一场好好打拿个 r k 1 rk1 rk1,最后十分钟被超了,三周个人赛没拿个 r k 1 rk1 rk1算是个小遗憾吧
题面
签到题 找到两侧同时开出的火车即可,输出相同的个数
#include
#define N 200200
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
int n,m,x,ans,cnt;
int t;
int main(){
read(t);
while(t--){
set<int> s;
ans=0;
read(n),read(m);
for(int i=1;i<=n;i++)read(x),s.insert(x);
for(int i=1;i<=m;i++){
read(x);
if(s.find(x)!=s.end())ans++;
}
cout<<ans<<endl;
}
}
题面
显然操作 2 2 2的贡献之和是每相邻两个数的差的绝对值,枚举遍历操作 1 1 1贡献最小的即可
#include
#define N 1000100
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(ll &x){
ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
bool cmp(ll x, ll b){
return x>b;
}
ll n,k,now,ans,t,a[N];
char s[N];
int main(){
read(t);
while(t--){
ans=now=0;
read(n);
for(int i=1;i<=n;i++)read(a[i]);
for(int i=2;i<=n;i++)ans+=abs(a[i]-a[i-1]);
for(int i=2;i<n;i++)now=max(now,abs(a[i]-a[i-1])+abs(a[i+1]-a[i])-abs(a[i+1]-a[i-1]));
now=max(now,abs(a[2]-a[1]));now=max(now,abs(a[n]-a[n-1]));
cout<<ans-now<<endl;
}
}
题面
大模拟一,把答案分为两种,一种是有底边构造高,一种是有高构造底边。
每次枚举一列或者一行的 0 − 9 0-9 0−9,如果只出现两次,那就更新两次答案:先以这两个为边,构造两侧最远的高。再以这两个中的一个构造底边,枚举两侧的高更新答案。
输入时维护最上面最下面最左边最右边的 0 − 9 0-9 0−9的行列数即可。
时间复杂度 O ( n 2 ) O(n^2) O(n2)。
#include
#define N 2020
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
bool cmp(int x, int b){
return x>b;
}
int n,sqr[N][N],t,le[15],ri[15],up[15],dn[15],ans[15],now[15][2],vis[15];
int main(){
read(t);
while(t--){
for(int i=0;i<=9;i++)le[i]=ri[i]=up[i]=dn[i]=ans[i]=vis[i]=0;
read(n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char chr=getchar();
while(chr<'0'||chr>'9')chr=getchar();
sqr[i][j]=chr&15;
if(!le[sqr[i][j]]||j<le[sqr[i][j]])le[sqr[i][j]]=j;
if(ri[sqr[i][j]]<j)ri[sqr[i][j]]=j;
if(!up[sqr[i][j]]||i<up[sqr[i][j]])up[sqr[i][j]]=i;
if(dn[sqr[i][j]]<i)dn[sqr[i][j]]=i;
vis[sqr[i][j]]++;
}
}
for(int j=1;j<=n;j++){
for(int i=0;i<=9;i++)now[i][0]=now[i][1]=0;
for(int i=1;i<=n;i++){
if(!now[sqr[i][j]][0])now[sqr[i][j]][0]=now[sqr[i][j]][1]=i;
else now[sqr[i][j]][1]=i;
}
for(int i=0;i<=9;i++){
if(now[i][1]==now[i][0]&&now[i][0]==0)continue;
int len=now[i][1]-now[i][0];
if(now[i][1]==now[i][0]){
len=max(now[i][1]-1,n-now[i][0]);
ans[i]=max(ans[i],max((j-le[i])*(len),(ri[i]-j)*(len)));
}
else{
ans[i]=max(ans[i],max((j-1)*(len),(n-j)*(len)));
len=max(now[i][1]-1,n-now[i][0]);
ans[i]=max(ans[i],max((j-le[i])*(len),(ri[i]-j)*(len)));
}
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<=9;j++)now[j][0]=now[j][1]=0;
for(int j=1;j<=n;j++){
if(!now[sqr[i][j]][0])now[sqr[i][j]][0]=now[sqr[i][j]][1]=j;
else now[sqr[i][j]][1]=j;
}
for(int j=0;j<=9;j++){
if(now[j][1]==now[j][0]&&now[j][0]==0)continue;
int len=now[j][1]-now[j][0];
if(now[j][1]==now[j][0]){
len=max(now[j][1]-1,n-now[j][0]);
ans[j]=max(ans[j],max((i-up[j])*(len),(dn[j]-i)*(len)));
}
else{
ans[j]=max(ans[j],max((i-1)*(len),(n-i)*(len)));
len=max(now[j][1]-1,n-now[j][0]);
ans[j]=max(ans[j],max((i-up[j])*(len),(dn[j]-i)*(len)));
}
}
}
for(int i=0;i<=9;i++){
if(vis[i]>1)printf("%d",ans[i]);
else putchar('0');
if(i==9)putchar('\n');
else putchar(' ');
}
}
}
/*
1
8
42987101
98289412
38949562
87599023
92834718
83917348
19823743
38947912
*/
题面
改第三个大模拟时间太久了 这题没时间做了 就是一道简单的数学题
首先一个 1 1 1的期望是 2 2 2,这个看样例就能看出来,推一下就是
E = 1 × 1 2 + 2 × 1 4 + . . . + n × 1 2 n E=\,\,\,\,\,\,\,\,\,\,\,\,\,1\times\frac{1}{2}+2\times\frac{1}{4}+...+n\times\frac{1}{2^n} E=1×21+2×41+...+n×2n1
2 E = 1 + 2 × 1 2 + 3 × 1 4 + . . . + n × 1 2 n − 1 2E=1+2\times\frac{1}{2}+3\times\frac{1}{4}+...+n\times\frac{1}{2^{n-1}} 2E=1+2×21+3×41+...+n×2n−11
下面减上面得 E = 1 + 1 2 + 1 4 + . . . + 1 2 n − 1 − 1 2 n , n → + ∞ E=1+\frac{1}{2}+\frac{1}{4}+...+\frac{1}{2^{n-1}}-\frac{1}{2^n},n\rightarrow+\infty E=1+21+41+...+2n−11−2n1,n→+∞时 E = 2 E=2 E=2
对于 1 1 1后面跟着 n n n个 0 0 0,假设现在已经走到了第 K K K个 0 0 0,设当前期望为 E k E_k Ek,则有
E k + 1 = ( E k + 1 ) × 1 2 + 2 ( E k + 1 ) × 1 4 + . . . + n ( E k + 1 ) × 1 2 n E_{k+1}=\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,\,(E_k+1)\times\frac{1}{2}+2(E_k+1)\times\frac{1}{4}+...+n(E_k+1)\times\frac{1}{2^n} Ek+1=(Ek+1)×21+2(Ek+1)×41+...+n(Ek+1)×2n1
2 E k + 1 = ( E k + 1 ) + 2 ( E k + 1 ) × 1 2 + 3 ( E k + 1 ) × 1 4 + . . . + n ( E k + 1 ) × 1 2 n − 1 2E_{k+1}=(E_k+1)+2(E_k+1)\times\frac{1}{2}+3(E_k+1)\times\frac{1}{4}+...+n(E_k+1)\times\frac{1}{2^{n-1}} 2Ek+1=(Ek+1)+2(Ek+1)×21+3(Ek+1)×41+...+n(Ek+1)×2n−11
下面减上面得 E k + 1 = ( E k + 1 ) × ( 1 + 1 2 + 1 4 + . . . + 1 2 n − 1 − 1 2 n ) , n → + ∞ E_{k+1}=(E_k+1)\times(1+\frac{1}{2}+\frac{1}{4}+...+\frac{1}{2^{n-1}}-\frac{1}{2^n}),n\rightarrow+\infty Ek+1=(Ek+1)×(1+21+41+...+2n−11−2n1),n→+∞时 E k + 1 = 2 ( E k + 1 ) E_{k+1}=2(E_k+1) Ek+1=2(Ek+1)
推出通项公式有 E k = 2 k + 2 − 2 E_k=2^{k+2}-2 Ek=2k+2−2。
因此我们知道了一段 100...0 100...0 100...0的期望,由于期望之间是线性关系,因此我们只需从大到小枚举 E k E_k Ek即可。
#include
#define N 2020
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(ll &x){
ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
int n,m,cnt[N],now;
ll t,x,frac[100];
int main(){
read(t);
frac[0]=2;
for(int i=1;i<=61;i++)frac[i]=frac[i-1]+1<<1;
while(t--){
read(x);
now=0;
if(x&1){
puts("-1");
continue;
}
for(int i=61;~i;i--){
while(x>=frac[i]){
cnt[++now]=1,x-=frac[i];
for(int j=1;j<=i;j++)cnt[++now]=0;
}
}
printf("%d\n",now);
for(int i=1;i<=now;i++)printf("%d ",cnt[i]);
puts("");
}
}
题面
输入一个字符串,在每一位判断一下换更优还是不换更优即可
#include
#define N 2002
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
int n,x,y,m,ans,t;
char s[N];
int main(){
read(t);
while(t--){
read(n),read(x),read(y),read(m);
scanf("%s",s);
ans=0;
for(int i=0;i<n;i++){
if(s[i]=='0')ans+=min(x,y+m);
else ans+=min(y,x+m);
}
cout<<ans<<endl;
}
}
题面
设 p = ⌈ n 2 ⌉ p=\lceil\frac{n}{2}\rceil p=⌈2n⌉,为什么要设呢,因为方便我打字,那个公式要打好久
求每一段第 p p p大的数和最大,我们利用贪心的思想,先将数组从大到小排序,先将数组的前 p p p大的数分给第一段,然后将后 n − p + 1 n-p+1 n−p+1小的分给第一段,以此类推,最终答案就是第 p , 2 p , . . . , k p p,2p,...,kp p,2p,...,kp大的数之和。
#include
#define N 1000100
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(ll &x){
ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
bool cmp(ll x, ll b){
return x>b;
}
ll n,k,now,ans,t,a[N];
char s[N];
int main(){
read(t);
while(t--){
ans=0;
read(n),read(k);
for(int i=1;i<=n*k;i++)read(a[i]);
sort(a+1,a+1+n*k,cmp);
if(n&1)now=(n+1)/2;
else now=n/2;
now=n-now+1;
for(int i=1;i<=k;i++){
ans+=a[i*now];
}
cout<<ans<<endl;
}
}
题面
大模拟二:小模拟,没寻思后面是个一样的模拟,早知道直接做后面那个题了
操作是在一个 2 × 2 2\times2 2×2的小方格中取三个数将 0 0 0变 1 1 1, 1 1 1变 0 0 0,我们设这个操作中没变的那个方格为中心方格。
一个性质就是在 2 × 2 2\times2 2×2的小方格中,以其他三个为中心方格做操作,会只改变该方格中一个块的数。所以用这个性质,每见到一个 1 1 1就这样做三次操作即可。题目要求的操作数少于 3 n m 3nm 3nm,边界条件的 3 3 3就是这么来的。
模拟即可
#include
#define N 2020
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
bool cmp(int x, int b){
return x>b;
}
int n,m,sqr[N][N],t,cnt;
int main(){
read(t);
while(t--){
read(n);read(m);
cnt=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char chr=getchar();
while(chr<'0'||chr>'9')chr=getchar();
sqr[i][j]=chr&15;
if(sqr[i][j])cnt+=3;
}
}
printf("%d\n",cnt);
for(int i=1;i<n;i++){
for(int j=1;j<m;j++){
if(sqr[i][j]==1){
printf("%d %d %d %d %d %d\n",i,j,i,j+1,i+1,j+1);
printf("%d %d %d %d %d %d\n",i,j,i,j+1,i+1,j);
printf("%d %d %d %d %d %d\n",i,j,i+1,j,i+1,j+1);
sqr[i][j]=0;
}
}
}
for(int j=1;j<m;j++){
if(sqr[n][j]==1){
printf("%d %d %d %d %d %d\n",n,j,n,j+1,n-1,j+1);
printf("%d %d %d %d %d %d\n",n,j,n-1,j,n-1,j+1);
printf("%d %d %d %d %d %d\n",n,j,n,j+1,n-1,j);
sqr[n][j]=0;
}
}
for(int i=1;i<n;i++){
if(sqr[i][m]==1){
printf("%d %d %d %d %d %d\n",i,m,i+1,m-1,i+1,m);
printf("%d %d %d %d %d %d\n",i,m,i,m-1,i+1,m);
printf("%d %d %d %d %d %d\n",i,m,i+1,m-1,i,m-1);
sqr[i][m]=0;
}
}
if(sqr[n][m]==1){
printf("%d %d %d %d %d %d\n",n,m,n-1,m,n,m-1);
printf("%d %d %d %d %d %d\n",n,m,n-1,m-1,n,m-1);
printf("%d %d %d %d %d %d\n",n,m,n-1,m,n-1,m-1);
sqr[n][m]=0;
}
}
}
题面
难版本的,我们考虑递推操作每碰到一个 1 1 1就把这个 1 1 1和下面两个数操作,这样如果不考虑下面的情况,最多 O ( n m ) O(nm) O(nm)就可以处理掉所有的 1 1 1,但是显然不能都这么做,因为最后两行要一起处理掉,所以我们先用上面的方法处理掉剩两行的情况,再单独处理最后两行。
最后两行我们从左往右按列递推,如果该列两个都为 1 1 1那就直接操作这两个和右边随便一个,如果有一个为 1 1 1就操作这个 1 1 1和右边两个,这样用 m m m次就可以操作 2 m 2m 2m个数,直到最后一个 2 × 2 2\times 2 2×2个小方格。 我们暴力解决这个小方格即可。因为要先输出操作数再输出操作,我也没想到我这一系列操作有什么方法可以先算出操作数,我就直接模拟两次了。
#include
#define N 2020
using namespace std;
typedef long long ll;
const ll mod=998244353;
inline void read(int &x){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
x=s*w;
}
bool cmp(int x, int b){
return x>b;
}
int n,m,sqr[N][N],a[N][N],t,cnt,now;
void print(int aa, int b, int c, int d, int ee, int f){
printf("%d %d %d %d %d %d\n",aa,b,c,d,ee,f);
a[aa][b]^=1,a[c][d]^=1,a[ee][f]^=1;
}
int main(){
read(t);
while(t--){
read(n);read(m);
cnt=now=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char chr=getchar();
while(chr<'0'||chr>'9')chr=getchar();
sqr[i][j]=a[i][j]=chr&15;
}
}
for(int i=1;i<=n-2;i++){
for(int j=1;j<m;j++){
if(sqr[i][j]==1)cnt++,sqr[i][j]^=1,sqr[i+1][j]^=1,sqr[i+1][j+1]^=1;
}
if(sqr[i][m]==1)cnt++,sqr[i][m]^=1,sqr[i+1][m]^=1,sqr[i+1][m-1]^=1;
}
for(int j=1;j<=m-2;j++){
if(!sqr[n-1][j]&&!sqr[n][j])continue;
if(sqr[n-1][j]&&sqr[n][j]){
cnt++;
if(sqr[n][j+1])sqr[n][j+1]^=1,sqr[n-1][j]^=1,sqr[n][j]^=1;
else sqr[n-1][j+1]^=1,sqr[n-1][j]^=1,sqr[n][j]^=1;
}
else if(sqr[n-1][j]&&!sqr[n][j])cnt++,sqr[n-1][j]^=1,sqr[n-1][j+1]^=1,sqr[n][j+1]^=1;
else if(!sqr[n-1][j]&&sqr[n][j])cnt++,sqr[n][j]^=1,sqr[n-1][j+1]^=1,sqr[n][j+1]^=1;
}
for(int i=n-1;i<=n;i++){
for(int j=m-1;j<=m;j++)now+=sqr[i][j];
}
if(now==4)cnt+=4;
if(now==3)cnt++;
if(now==2)cnt+=2;
if(now==1)cnt+=3;
cout<<cnt<<endl;
for(int i=1;i<=n-2;i++){
for(int j=1;j<m;j++){
if(a[i][j]==1)print(i,j,i+1,j,i+1,j+1);
}
if(a[i][m]==1)print(i,m,i+1,m,i+1,m-1);
}
for(int j=1;j<=m-2;j++){
if(!a[n-1][j]&&!a[n][j])continue;
if(a[n-1][j]&&a[n][j]){
if(a[n][j+1])print(n,j+1,n-1,j,n,j);
else print(n-1,j+1,n-1,j,n,j);
continue;
}
else if(a[n-1][j]&&!a[n][j])print(n-1,j,n-1,j+1,n,j+1);
else if(!a[n-1][j]&&a[n][j])print(n,j,n-1,j+1,n,j+1);
}
if(now==4){
print(n-1,m,n,m-1,n,m);//n-1,m-1
print(n-1,m-1,n,m-1,n,m);//n-1,m
print(n-1,m-1,n-1,m,n,m);//n,m-1
print(n-1,m-1,n-1,m,n,m-1);//n,m
}
if(now==3){
if(!a[n-1][m-1])print(n-1,m,n,m-1,n,m);
else if(!a[n-1][m])print(n-1,m-1,n,m-1,n,m);
else if(!a[n][m-1])print(n-1,m-1,n-1,m,n,m);
else if(!a[n][m])print(n-1,m-1,n-1,m,n,m-1);
}
if(now==2){
if(a[n-1][m-1]&&a[n-1][m])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n,m-1,n,m);
else if(!a[n-1][m-1]&&!a[n-1][m])print(n-1,m-1,n-1,m,n,m),print(n-1,m-1,n-1,m,n,m-1);
else if(a[n-1][m-1]&&a[n][m])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m-1);
else if(!a[n-1][m-1]&&!a[n][m])print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m);
else if(a[n-1][m-1]&&a[n][m-1])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m);
else if(!a[n-1][m-1]&&!a[n][m-1])print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m-1);
}
if(now==1){
if(a[n-1][m-1])print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m),print(n-1,m-1,n-1,m,n,m-1);
else if(a[n-1][m])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m),print(n-1,m-1,n-1,m,n,m-1);
else if(a[n][m-1])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m-1);
else if(a[n][m])print(n-1,m,n,m-1,n,m),print(n-1,m-1,n,m-1,n,m),print(n-1,m-1,n-1,m,n,m);;
}
/*for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)printf("%d ",a[i][j]);
puts("");
}*/
}
}