文章目录
- [A. Sakurako and Kosuke](#A. Sakurako and Kosuke)
- [B. Sakurako and Water](#B. Sakurako and Water)
- [C. Sakurako's Field Trip](#C. Sakurako's Field Trip)
- [D. Kousuke's Assignment](#D. Kousuke's Assignment)
- [E. Sakurako, Kosuke, and the Permutation](#E. Sakurako, Kosuke, and the Permutation)
- [F. Kosuke's Sloth](#F. Kosuke's Sloth)
A. Sakurako and Kosuke
思路
签到题,直接判断奇偶即可
code
cpp
void solve(){
int n;cin >> n;
if(n & 1) cout << "Kosuke" << endl;
else cout << "Sakurako" << endl;
return ;
}
B. Sakurako and Water
思路
考点:模拟
从头开始遍历,如果当前数 < 0,则说明这个数需要进行增加操作,那就遍历这个数的对角线,找出最大值,将这个对角线都加上最大值即可
将这些最大值全部累加,最后输出即可
code
cpp
const int N=1000;
int a[N][N];
void solve(){
int n;cin >> n;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
cin >> a[i][j];
}
int ans=0;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j){
if(a[i][j]<0){
int k=min(n-i+1,n-j+1);
int s=0;
for(int z=0;z<k;++z){
if(a[i+z][j+z]<0) s=max(s,abs(a[i+z][j+z]));
}
for(int z=0;z<k;++z){
a[i+z][j+z]+=s;
}
ans+=s;
}
}
cout << ans << endl;
return ;
}
C. Sakurako's Field Trip
思路
考点:模拟
暴力解法,我们只需要考虑每一项 i i i 和它的镜像 n − i + 1 n-i+1 n−i+1 前后四项的值
如果这四个数有3个数的值相同,ans++,如果这四个数都相同,ans+=2
这时还需要考虑边界的问题,如果这个数为奇数并且遍历到中间这个数
那么我们就只需要考虑3个数,中间这个数和它前后这两个数
- 如果这三个数都相同,ans+=2
- 中间的数和前面的数相同或者中间的数和后面的数相同,ans++
如果这个数为偶数并且遍历到中间这两个数
那么我们只需要判断这两个数是否相同即可,相同ans++
讲起来有点复杂,实际上代码挺简单的
code
cpp
int a[N];
void solve(){
int n;cin >> n;
for(int i=1;i<=n;++i) cin >> a[i];
int ans=0;
for(int i=1,j=n;i<j;++i,--j){
map<int,int> m;
m.clear();
if(i+1<j-1){
m[a[i]]++,m[a[i+1]]++,m[a[j]]++,m[a[j-1]]++;
for(auto x : m){
if(x.se==3) ans++;
if(x.se==4) ans+=2;
}
}
else if(i+1==j-1){
int x=a[i],y=a[i+1],z=a[j];
if(x==y){
if(x==z) ans+=2;
else ans+=1;
}
else{
if(y==z) ans+=1;
}
}
else{
if(a[i]==a[j]) ans+=1;
}
}
cout << ans << endl;
return ;
}
D. Kousuke's Assignment
思路
考点:前缀和
对于数组 a a a ,先计算出它的前缀和,对于这个前缀和,我们维护当前 i i i 的上一个下标
如果遇见相同的前缀和,查询该前缀和的上一个下标是否小于上一段线段的结束位置
如果小于则选择,更新该前缀和的上一个下标为 i − 1 i-1 i−1
code
cpp
int a[N],sum[N];
void solve(){
int n;cin >> n;
for(int i=1;i<=n;++i){
cin >> a[i];
sum[i]=sum[i-1]+a[i];
}
int ans=0,mx=-1;
map<int,int> m;
m[0]=0;
for(int i=1;i<=n;++i){
if(m.count(sum[i])){
if(m[sum[i]]>mx){
ans++;
mx=i-1;
}
}
m[sum[i]]=i;
}
cout << ans << endl;
return ;
}
E. Sakurako, Kosuke, and the Permutation
思路
我们可以将这题看成一个环, i − > p i − > p p i − > ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ − > i i ->p_i->p_{pi}->······->i i−>pi−>ppi−>⋅⋅⋅⋅⋅⋅−>i 为一个循环节
我们需要将这个环拆分成若干个自环和环节数为2的环
如果这个环为自环,代表自己指向自己 ,如果这个环的环节为2,代表这个环里的两个数相互指向对面
把玩一下不难发现,替换 p p i = i p_{pi}=i ppi=i 优于 p i = i p_i=i pi=i 的操作
因为进行 p i = i p_i=i pi=i 的替换只能保证一个数是准确的,让这个数形成自环
而进行 p p i = i p_{pi}=i ppi=i 不仅可以保证一个数是准确的,还有可能会形成环节为2的环
因此我们只需要考虑 p p i = i p_{pi}=i ppi=i 的操作即可,用map存储环,每次进行替换操作维护map即可
code
cpp
int a[N];
void solve(){
int n;cin >> n;
map<int,int> m;
for(int i=1;i<=n;++i){
cin >> a[i];
m[a[i]]=i;
}
int ans=0;
for(int i=1;i<=n;++i){
if(a[i]!=i && a[a[i]]!=i){
int s=m[i];
int t=a[i];
swap(a[s],a[t]);
m[a[s]]=s;
m[a[t]]=t;
ans++;
}
}
cout << ans << endl;
return ;
}
F. Kosuke's Sloth
思路
斐波那契数列在模 k k k 意义下有周期性(皮萨诺周期),且这个周期 < = 6 k <=6k <=6k
暴力枚举求出周期 r r r,则第 n n n 个数的下标为 r n rn rn
code
cpp
int f[N];
void solve(){
int n,k;
cin >> n >> k;
f[1]=1,f[2]=1;
if(k==1){
cout << n%mod << endl;
return ;
}
int ans=0;
for(int i=3;i<=6e5+5;++i){
f[i]=(f[i-1]+f[i-2])%k;
if(f[i]%k==0){
ans=i;
break;
}
}
cout << ((n%mod)*(ans%mod))%mod << endl;
return ;
}