G. Fibonacci
题目大意:
f n f_n fn为斐波那契数列, f 1 = 1 , f 2 = 1 , f n = f n − 2 + f n − 1 f_1=1,f_2=1,f_n=f_{n-2}+f_{n-1} f1=1,f2=1,fn=fn−2+fn−1
计算 ∑ i = 1 n ∑ j = i + 1 n g ( f i , f j ) \sum_{i=1}^n\sum_{j=i+1}^ng(f_i,f_j) ∑i=1n∑j=i+1ng(fi,fj)
其中,若 x ⋅ y x\cdot y x⋅y为偶数, g ( x , y ) = 1 g(x,y)=1 g(x,y)=1,否则 g ( x , y ) = 0 g(x,y)=0 g(x,y)=0。
思路:
观察斐波那契数列,可以发现:
在奇偶性上,该数列按“奇数、奇数、偶数”的顺序循环排列
每三个数字按奇偶性一循环。
由于
g
(
x
)
g(x)
g(x)只在自变量为偶数时,值为1,所以只要关注偶数就好。
给定n个斐波那契数,则偶数个数为
k
=
n
/
3
k=n/3
k=n/3,奇数个数为n-k。
在n个数字中任意选择两个不同的数字,其乘积为偶数,有以下两种情况:
1、偶数
×
\times
×偶数:
k
×
(
n
−
k
)
k\times(n-k)
k×(n−k)
2、偶数
×
\times
×奇数:
C
k
2
C_k^2
Ck2
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
ll C(ll n,ll m){
if(m>n) return 0;
ll fz=1,fm=1;
for(int i=n-m+1;i<=n;i++) fz*=i;
for(int i=1;i<=m;i++) fm*=i;
return fz/fm;
}
int main(){
ll n;
scanf("%lld",&n);
ll k=n/3;
ll ans=k*(n-k);
ans+=C(k,2);
printf("%lld\n",ans);
return 0;
}
M. Gitignore
题目大意:
给出n个要删除的文件路径,同时给出m个不能删除的文件路径。每次删除都只能删除一个文件或者一个文件夹(包括该文件夹内的所有内容),问最少需要删除多少个路径。
思路:
1、题目问最少要删除多少个路径,最省事的删法当然是整个文件夹一起删除(如果可以的话),所以我们其实应该先考虑哪些不能直接删除的文件路径,对于其他的文件,直接把文件夹删了就行,不过要注意不要重复删除(同一个文件夹只删一次)
2、对于不能删除的路径:
对其每一条子路径都要进行标记,都不能删除
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
map<string,int>mp;
int main(){
int t;
cin>>t;
while(t--){
int n,m;
string s[maxn];
cin>>n>>m;
mp.clear();//注意多组样例,每次清空
int sum=n;
for(int i=0;i<n;i++){
cin>>s[i];
}
for(int i=0;i<m;i++){
string a;
cin>>a;
string tmp="";
for(int j=0;j<a.length();j++){
tmp=a[j]+tmp;//所有子路径都需标记,都不能删除
if(a[j]=='/'){
// cout<<"tmp: "<<tmp<<endl;
mp[tmp]=1;
}
}
}
for(int i=0;i<n;i++){
s[i]+="/";
string tmp="";
for(int j=0;j<s[i].length();j++){
tmp=s[i][j]+tmp;
if(s[i][j]=='/'){
// cout<<"tmp: "<<tmp<<endl;
if(mp[tmp]==0){//如果当前路径并未被标记过,说明该路径可以直接删除
mp[tmp]=2;//标记为2:可以删除
}
else if(mp[tmp]==2){//当前路径可以直接删除
sum--;
break;//后面的文件路径无需再管
}
}
}
}
cout<<sum<<endl;
}
return 0;
}
B. Mine Sweeper II
题目大意:
扫雷游戏,"X"表示雷区, “.” 表示无雷区。每个无雷区上都有一个数字,记录该位置周围8个方向地雷的个数。现在给出A和B两张地图,它们的无雷区数字之和分别为sumA和sumB,求能否在n*m/2次以内改变B图,使得sumA=sumB。如果可以,输出修改之后的地图B,否则输出-1。
思路:
对于同一幅地图,将其中的雷区和无雷区位置对调,所得的无雷区数字之和是不变的!
题目给了nm/2次的限制,很容易想到的是:
如果A和B,相应位置,状态不同(此处状态指的是雷区、非雷区)的个数小于等于该值,则直接把B改成跟A一模一样,也不会超出次数。
但是如果大于该值,那就需要逆向思维,把A图所有位置的状态逆转(雷区变为非雷区,非雷区变为雷区),那么此时A和B位置相同但状态不同的数量一定是小于nm/2的!!!然后把B修改成A逆转之和的状态就可以了。
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e3+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
char a[maxn][maxn],b[maxn][maxn];
int main(){
int n,m;
cin>>n>>m;
int mmax=(m*n)/2;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>a[i][j];
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>b[i][j];
}
}
int cnt=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(a[i][j]!=b[i][j]) cnt++;
}
}
if(cnt<=mmax){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cout<<a[i][j];
}
cout<<endl;
}
}
else{
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(a[i][j]=='.') cout<<"X";
else cout<<".";
}
cout<<endl;
}
}
return 0;
}