A题 小苯的区间和疑惑题
用双向dp,dp[i]表示以第i位为结尾,从开始带第i位的最大区间大小,dpreverse[i]表示以第i位开始,到结尾的最大区间和,那么包含第i位置的最大区间和为dp[i]+dpreverse[i]-a[i];
解决代码如下
#include<iostream>
using namespace std;
int main (){
int n;
cin>>n;
long long dp[n+2];
long long dpreverse[n+2];
long long a[n+2];
for(int i=1;i<=n;i++)
cin>>a[i];
dp[0]=0;
dpreverse[n+1]=0;
for(int i=1;i<=n;i++){
if(dp[i-1]<=0)
dp[i]=a[i];
else
dp[i]=dp[i-1]+a[i];
}
for(int i=n;i>=1;i--){
if(dpreverse[i+1]<=0)
dpreverse[i]=a[i];
else
dpreverse[i]=dpreverse[i+1]+a[i];
}
for(int i=1;i<=n;i++)
cout<<dp[i]+dpreverse[i]-a[i]<<" ";
return 0;
}
B题 小苯的三元组
这一道题有两种思路,当然都不是我想出来的,当时写这道题的时候想着按照质数筛法筛出来每一位合适的数,统计一个数的倍数在数组中的个数,再找一个数的因数在数组中的个数,最后相乘,但是思路模糊也想不出来好的解决办法,下面是大佬的代码和相应的两种思路
法一:这三个数字的关系为前者是后者的因数,即c%b==0,b%a==0;
先用哈希表统计各个数字出现的次数,没有的为0;
然后遍历第一位i,从1到N,N为极大数,然后遍历到第一个存在的数字,然后再寻找第二个数字j,第二个数字为了满足可b%a==0的性质只能够以i为公差递增,同时在j数字存在的情况下寻找k,同理,k也以j为公差递增,最后找到合适的k值,那么统计次数ans=nums[i]*nums[j]*nums[k];
最后输出ans,解决代码如下
#include<iostream>
#include<map>
#include<algorithm>
typedef long long ll;
const ll N=200000;
ll nums[N];
using namespace std;
int main (){
ll n;
cin>>n;
for(int i=0;i<n;i++){
ll x;
cin>>x;
nums[x]++;
}
ll ans=0;
for(int i=1;i<=N;i++){
if(nums[i]){
for(int j=i;j<=N;j+=i){
if(nums[j]){
for(int k=j;k<=N;k+=j){
if(nums[k])
ans+=(nums[i]*nums[j]*nums[k]);
}
}
}
}
}
cout<<ans;
return 0;
}
第二个思路:
第二个思路,遍历每一位,统计以每一位为中间值的话满足题意的个数;
先预处理,lcd[x]表示数组中以x为因数的个数,即已知x就可以知道lcd[x](即第三个位置的可能情况);nums[x]表示x在数组中的个数,不存在的话为0,这样可以便于统计x的因数在数组中的个数和
解决思路
#include<iostream>
#include<map>
#include<cmath>
#include<algorithm>
int lcd[1000000];
int d[1000000];
using namespace std;
int main (){
int n;
cin>>n;
int a[n];
for(int i=0;i<n;i++){
int x;
cin>>a[i];
x=a[i];
for(int i=1;i<=sqrt(x);i++){
if(x%i!=0)
continue;
lcd[i]++;
if(x/i!=i) lcd[x/i]++;
}
d[x]++;
}
long long ans=0;
for(int i=0;i<n;i++){
int x;
x=a[i];
int c1=0,c2=0;
c2=lcd[x];
for(int j=1;j<=sqrt(x);j++){
if(x%j!=0) continue;
c1+=d[j];
if(x/j!=j) c1+=d[x/j];
}
ans+=c1*c2;
}
cout<<ans;
return 0;
}
C题 小红的 CUC
签到题
D题 小红的矩阵构造(一)
这一题也是不会写,看了大佬的思路,大有启发,接下来是三种思路
第一种思路,
仔细审题,观察规律,如果一个位置行数+列数>n的话,那么这个位置就是一,反之则为零
解决代码
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
int a[10000],b[10000];
int s[1010];
int mp[1010][1010];
int main (){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
mp[i][j]=a[i]+b[j]>n?1:0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cout<<mp[i][j];
cout<<endl;
}
return 0;
}
第二种思路
矩阵是由一条条列矩阵形成,如果将每一条列矩阵都正确处理,就能够得出正确答案,
首先列数列的形成顺序是从多到少的,即先生成含有n个数的列数列,再生成含有n-1一个数字的列数列,其中缺少生成的那个数来自于某一行只能有一个数字,也就是生成列数列,行数列是限制列数列生成的条件,比如案例 1,2,3 和 1,2,3;
先考虑数最多的列,即第三列,同时没有行来约束,那么第三列全部数字为1;
然后考虑数第二多的列,即第二列,这是需要加入行带来的限制条件,即让第一行(再生成列的过程中的第一个数字),在生成第二列,加入行数第二少的限制条件
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
pair<int,int> a[10000],b[10000];
int s[1010];
int mp[1010][1010];
int main (){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].first;
a[i].second=i;
}
for(int i=1;i<=n;i++){
cin>>b[i].first;
b[i].second=i;
}
sort(a+1,a+n+1);
sort(b+1,b+n+1);
for(int i=1;i<=n;i++){
int cnt=0;
int x=b[n-i+1].second;
for(int j=1;j<=n;j++){
if(s[j])
continue;
else{
mp[j][x]=1;
cnt++;
}
}
if(cnt!=n-i+1){
cout<<-1;
return 0;
}
s[a[i].second]=1;
}
for(int i=1;i<=n;i++){
for(int j=1 ; j<=n;j++)
cout<<mp[i][j];
cout<<endl;
}
return 0;
}
第三种思路
列的先后顺序为多的先填,然后每一行填的个数已经决定好了,列多的先填,行次数用完的话剩下的就为0,这个思路应该是最容易理解的,解决代码如下
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
int a[10000];
pair<int,int>b[10000];
int s[1010];
int mp[1010][1010];
bool cmp(pair<int,int> a,pair<int,int> b){
return a.first>b.first;
}
int main (){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i].first;
b[i].second=i;
}
sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i]){
mp[i][b[j].second]=1;
a[i]--;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
cout<<mp[i][j];
cout<<endl;
}
return 0;
}
E题 小红的矩阵构造(二)
#include<iostream>
using namespace std;
int main (){
int n,m,k;
cin>>n>>m>>k;
int c=(n-1)*(m-1);
if(c<k){
cout<<-1;
return 0;
}
char ch[n+1][m+1];
for(int i=1;i<=n;i++)
ch[i][1]='1';
for(int j=1;j<=m;j++)
ch[1][j]='1';
int cnt=0;
for(int i=2;i<=n;i++){
for(int j=2;j<=m;j++){
if(cnt>=k){
ch[i][j]='0';
continue;
}
ch[i][j]='1';
cnt++;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<ch[i][j];
}
cout<<endl;
}
return 0;
}
观察规律,先命令第一行和第一列为1,接下来每多一个矩阵就相当于增加一个一
H题 小红的生物实验
这一题我的思路不能正常运行,不知道为什么,我认为消去细胞壁的条件即将每一行的第一个和最后一个删去,把每一列的第一个和最后一个删去,但是答案错误;
接下来是dfs的思路,即标记所有外部环境的区域,然后记录其接触的细胞壁的位置,最后遍历,将外部环境,接触的细胞壁输出为'.',将未被标记的‘*’正常输出
#include<iostream>
using namespace std;
int n,m;
char a[1010][1010];
int vis[1010][1010];
void dfs(int x,int y){
if(x<1||x>n||y<1||y>m)
return ;
if(vis[x][y])
return ;
vis[x][y]=1;
if(a[x][y]=='*'){
a[x][y]='.';
return ;
}
dfs(x+1,y);
dfs(x-1,y);
dfs(x,y+1);
dfs(x,y-1);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
cin>>a[i][j];
}
for(int i=1;i<=n;i++)
dfs(i,1),dfs(i,m);
for(int i=1;i<=m;i++)
dfs(1,i),dfs(n,i);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
cout<<a[i][j];
cout<<endl;
}
return 0;
}