分数
T1:三个(three)0'(100)
T2:合体(fit)0'(70)
T3:矩阵(matrix)0'(0)
T4:数对(pair)0'(5)
总分:0'(175)
注:文件错误,freopen里w和r写反爆零了,括号里是重判分。
题解
T1:三个(three)
题面:
现在科学家在培养三种微生物,这三种微生物每一秒都会繁殖出新的微生物,具体规则为:
A 类微生物每一秒会繁殖出个
类微生物,
个 B 类微生物,
个
类微生物。
B 类微生物每一秒会繁殖出个
类微生物,
个 C 类微生物。
C 类微生物每一秒会繁殖出个
类微生物,
个 B 类微生物。
假设所有的微生物都不会死亡,一开始培养皿中有 三种微生物各
个,现在问你
秒后
三种微生物分别有奇数个还是偶数个。
赛时总结:
一眼,稳定发挥。
思路:
按规律暴力求解每一秒的生物数,注意一点,每一个被分裂出的生物也能分裂,要边运算边取模,不然会爆int(开long long也不行)。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
cin>>n;
int a=1,b=1,c=1;
while(n--){
int x=a,y=b,z=c;
a=(x+x+2*y+z)%2,b=(y+x+z)%2,c=(z+x+2*y)%2;
}
if(a%2==1) cout<<"odd\n";
else cout<<"even\n";
if(b%2==1) cout<<"odd\n";
else cout<<"even\n";
if(c%2==1) cout<<"odd\n";
else cout<<"even\n";
return 0;
}
T2:合体(fit)
题面:
现在有个大小范围在
中的整数
,并且你获得了一项魔法能力。
施加一次魔法能力后,可以将两个相同的数字合并成一个数字,并且这个数字为原来的数字,例如:
有这两个数字,施加一次魔法能力后可以将这两个数字合并成一个数字
。
现在有次询问,每次询问给你一个整数
,你可以施加任意次数魔法能力,问你这
个整数最多能得到多少个整数
?
赛时总结:
下次记得关同步。
思路:
可以预处理所有的数,但肯定是会爆TLE的,所以可以写个小递推
设状态:
然后带入算就行。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005],q,t[1000005],f[1000005];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
t[a[i]]++;
}
f[1]=t[1];
for(int i=1;i<=m;i++){
f[i]=f[i-1]/2+t[i];
}
cin>>q;
while(q--){
int x;
cin>>x;
cout<<f[x]<<'\n';
}
return 0;
}
T3:矩阵(matrix)
题面:
现在给你一个行
列的矩阵,矩阵上每个格子有一个整数,其中第
行第
列对应的格子上的整数为
。
现在定义该矩阵的一个子矩阵的快乐值为该子矩阵上的所有数字的异或和。
一组数字的异或和为
。(其中
表示按位异或运算)
现在问你,该矩阵的所有子矩阵的快乐值之和为多少?
赛时总结:
打了好久的大模拟,还是写炸了。
思路:
考虑将二维数组压成一维的
枚举起始行和终止行
,这个范围内的每一列都求异或值(例如
为
的异或值)。之后再对于x数组求前缀异或值,然后枚举其左右端点,计算区间异或值即可。
但是这样的时间复杂度为,还是会爆掉。
对于上述方案,枚举完起始行和终止行之后,还需要去计算结果,这一部分可以考虑优化。
按位去考虑,对于某个区间,按位异或之后的值的某一位,是否为1。只需要考虑这个区间内的这一位的1的个数是奇数个还是偶数个。
也可以考虑数组
,按位考虑,某一位如果想被累计到答案里,那么
的这一位和
的这一位就不相同。所以可以考虑把
拆位,如果当前这一位是
,那么就考虑它前面这一位是
的情况有多少个,反之同理。
AC代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=305;
int n,m,a[N][N],b[N],sum[N];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
ll ans=0;
for(int u=1;u<=n;u++){
memset(b,0,sizeof(b));
for(int d=u;d<=n;d++){
for(int j=1;j<=m;j++){
b[j]^=a[d][j];
sum[j]=sum[j-1]^b[j];
}
for(int p=0;p<10;p++){
ll cnt[2]={1,0};
for(int j=1;j<=m;j++){
int t=(sum[j]>>p)&1;
ans+=(1<<p)*cnt[t^1];
cnt[t]++;
}
}
}
}
cout<<ans;
return 0;
}
T4:数对(pair)
题面:
给你一个长度为的数列
。
再给你一个长度为的数列
。
现在再再再给你一个正整数,让你生成一个长度为
的数列
。
其中满足 。
现在问你数列中有多少个数对
满足
且
?
赛时总结:
没看懂,直接输出0。
思路:
我们观察到数组是可以分成
块,每一块有
个数字。 可以对块内求逆序,然后再块与块之间求。
对于块内
观察到值域非常小,我们可以对数组记录数字出现次数。
枚举到当前数字,计算逆序数时,可以枚举比
大的数字的出现次数即可。也就是记录
。
考虑数组后续需要变化。所有我们记录一个数组
。表示为对于
数组所有数组都加
之后,逆序数为多少。
对于块与块
我们可以记录之前所有数字的出现次数,当前块一定是在之前块的后面,直接枚举值域,统计逆序数即可。
AC代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5;
int n,m,p,a[N],b[N];
ll cntb[11],res[11],vis[11];
void write(__int128 x){
if(x>9) write(x/10);
putchar(char(x%10+'0'));
}
int main(){
cin>>n>>m>>p;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++){
cin>>b[i];
cntb[b[i]]++;
}
for(int k=0;k<p;k++){
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++){
for(int j=b[i]+1;j<p;j++){
res[k]+=vis[j];
}
vis[b[i]]++;
b[i]=(b[i]+1)%p;
}
}
__int128 ans=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
ans+=res[a[i]];
for(int k=0;k<p;k++){
for(int j=(a[i]+k)%p+1;j<p;j++){
ans+=cntb[k]*vis[j];
}
}
for(int k=0;k<p;k++){
vis[(a[i]+k)%p]+=cntb[k];
}
}
write(ans);
return 0;
}
总结
服了,文件还能写错 。
这次爆零了,也是模拟首爆,下次记得别把r和w写反了,第二题也就差一点,被卡了cin、cout,下次记得关同步,有史以来因为个人疏漏出错最多的一次,希望下次能吸取教训吧。
早日AKJ组!!!
最后把文件输入输出贴在这里
freopen("xxx.in","r",stdin);
freopen("xxx.out","w",stdout);