第一题:路径计数
评析:dp题,类似数字三角形,加个判断,如果是0,直接将f[i][j]数组置0,否则正常走路就可以
#include<bits/stdc++.h>
using namespace std;
int f[105][105],a[105][105],n,ans;
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
cin>>a[i][j];
//f[0][1]=1;
int x=1e9+7;
f[0][1]=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
if (a[i][j]==0) f[i][j]=0;
else f[i][j]=(f[i-1][j]+f[i][j-1]) % x;
}
cout<<f[n][n];
}
第二题:最大和上升子序列
评析:还是dp,两个最基础模型最长上升子序列和最大子段和的结合体
#include<bits/stdc++.h>
using namespace std;
int ans,n,f[1005],a[1005];
int main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++)
for (int j=i;j>=1;j--)
{
if (a[i]>=a[j])
f[i]=max(f[j]+a[i],f[i]);
}
for (int i=1;i<=n;i++) ans=max(ans,f[i]);
cout<<ans;
}
第三题:加一
注意输入输出用scanf,printf
评析:比较难的一个dp,我们设定状态数组f[N] [10],N是m的上限:2*10^5,10是0~9,f[i] [j]的意思是:原本是j的数位经过i次操作后变成了f[i] [j]位。比如f[1] [9],就是原本这个位置上是9,经过了1次操作后,变成了10,即两位数。
状态转移方程有两种情况,j=0~8是:f[i] [j-1]=f[i-1] [j]; j=9时是f[i] [9]=(f[i-1] [0]+f[i-1] [1])%MOD。因为9加完后是10,位数就是1和0加起来。其余则和+1前的数一样。最后我们以字符串形式读入数字,以数字形式读入操作次数m,然后根据数字每位上的数,将f[m] [j]累加起来即可,注意要取模
#include<bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
long long f[200060][10];
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i <= 9; i++)f[0][i] = 1;
for (int i = 1; i <= 200010; i++)
{
for (int j = 1; j <= 9; j++)f[i][j - 1] = f[i-1][j];
f[i][9] = (f[i-1][1] + f[i-1][0]) % MOD;
}
while (n--)
{
char str[20];
int m, res = 0;
scanf("%s %d", &str, &m);
int len = strlen(str);
for (int i = 0; i < len; i++)
{
res += f[m][str[i] - '0'];
res %= MOD;
}
printf("%d\n",res);
}
return 0;
}
第四题:跳跳
评析:最大公约数,我们发现对于每一次魔法所需要的距离大小每一次都要尽可能短,因为每次移动魔法可以用很多次嘛,所以我们先预处理得到每一步的距离差,接着都除以两两间的最大公约数,注意要加绝对值,因为会出现负值,接着就是排序,比较,输出了
#include<bits/stdc++.h>
using namespace std;
int sum,n,a[250000],b[250000],k[250000],x[500],y[500];
struct point
{
int x;
int y;
}c[250000];
bool cmp(point a,point b)
{
return a.x<=b.x;
}
int main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>x[i]>>y[i];
int tot=0;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (i!=j)
{
tot++;
a[tot]=x[i]-x[j];
b[tot]=y[i]-y[j];
k[tot]=abs(__gcd(a[tot],b[tot]));
c[tot].x=a[tot]/k[tot];
c[tot].y=b[tot]/k[tot];
//cout<<a[tot]<<" "<<b[tot]<<" "<<k[tot]<<" "<<c[tot].x<<" "<<c[tot].y<<endl;
}
}
}
sort(c+1,c+tot+1,cmp);
for (int i=1;i<=tot-1;i++)
{
if ((c[i].x!=c[i+1].x && c[i].y!=c[i+1].y) || (c[i].x==c[i+1].x && c[i].y!=c[i+1].y) || (c[i].x!=c[i+1].x && c[i].y==c[i+1].y)) sum++;
//if (c[i].x==c[i+1].x && c[i].y==c[i+1].y) sum--;
}
cout<<sum+1;
}
第五题:异和异或
评析:一个思考题吧,多在纸上画一画,接可以看出,其实除全零外只有两种操作,还是可逆的,那么很明显的我们最后可以将任意带有1的字符串转化为1111……,除了全0,那么不就转换成了判断一个字符串里面有没有1的思路了吗,当然记得判断一下长度
#include<bits/stdc++.h>
using namespace std;
int f1,f2,len1,len2,n;
string s,t;
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>s>>t;
int len1=s.length();
int len2=t.length();
if (len1 != len2)
{
cout<<"NO"<<endl;
continue;
}
else
{
for (int j=0;j<len1;j++)
if (s[j]=='1') f1=1;
for (int j=0;j<len2;j++)
if (t[j]=='1') f2=1;
if (f1==f2) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
f1=0;
f2=0;
continue;
}
}
return 0;
}
第六题:01序列
评析:前缀和
暴力做法可以求出所有的前缀和sum[i],只要sum[i]-sum[j]=k,[j+1,i]就是符合的子串区间
但这样统计太慢,其实到i点的sum[i]只要知道前面有多少sum[j]=sum[i]-k,而前缀和sum是单调不下降的
所以只要统计含1数量为sum[i]-k的前缀和数量有多少,这些j肯定是连续的,这些j的数量就是使得[j+1,i]内含有k个1的数量
用d[i]记录前缀和为i的数量,当前缀和sum>=k时,d[sum-k]的数量就可以累加到答案
记得判断一下全0 的情况
#include<bits/stdc++.h>
using namespace std;
long long k,ans,n,d[1000005],sum,f;
char s[1000005];
int main()
{
d[0]=1;
cin>>k;
scanf("%s",s+1);
n=strlen(s+1);
if (k==0)
{
for (int i=1;i<=n;i++)
{
if (s[i]=='1') f=1;
}
if (f==0)
{
cout<<(n+1)*n/2;
return 0;
}
}
for (int i=1;i<=n;i++)
{
sum+=s[i]-'0';
if (sum>=k) ans+=d[sum-k];
d[sum]++;
}
cout<<ans<<endl;
}
第七题:出栈序列判断
评析:栈,不断判断该数是不是栈顶元素,还没入栈就push,再pop
#include<bits/stdc++.h>
using namespace std;
int n,x,l,top,s[100005];
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
if (s[top]!=x)
{
for (int j=l+1;j<=x;j++)
{
printf("push %d\n",j);
s[++top]=j;
}
l=x;
}
printf("pop\n");
top--;
}
}
第八题:序列维护
评析:stl基本操作,但我忘了,还是得多复习
#include<bits/stdc++.h>
using namespace std;
vector<int>v;
int n,x,y;
string s;
int main()
{
cin>>n;
for (int i=0;i<n;i++)
{
cin>>s;
if (s[0]=='i')
{
cin>>x>>y;
v.insert(v.begin()+x,y);
}
else if (s[0]=='d')
{
cin>>x;
v.erase(v.begin()+x-1);
}
else
{
cin>>x;
cout<<v[x-1]<<endl;
}
}
}
第九题:网格判断
评析:模拟题,分开判断行列W,B的个数,然后判断不能连续三个同种颜色就🆗了
#include<bits/stdc++.h>
using namespace std;
char ch[30][30];
int n,f=1,sum1,sum2;
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
cin>>ch[i][j];
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (ch[i][j]==ch[i][j-1] && ch[i][j]==ch[i][j+1])
{
f=0;
cout<<f;
return 0;
}
if (ch[i][j]=='W') sum1++;
else sum2++;
//cout<<sum1<<" "<<sum2<<endl;
}
if (sum1==sum2) f=1;
else
{
f=0;
cout<<f;
return 0;
}
sum1=0;
sum2=0;
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (ch[j][i]==ch[j-1][i] && ch[j][i]==ch[j+1][i])
{
f=0;
cout<<f;
return 0;
}
if (ch[j][i]=='W') sum1++;
else sum2++;
}
if (sum1==sum2) f=1;
else
{
f=0;
cout<<f;
return 0;
}
sum1=0;
sum2=0;
}
cout<<f;
}
第十题:整齐的数组
评析:又是最大公约数,大概操作和跳跳差不多
#include<bits/stdc++.h>
using namespace std;
int t,n,a[105],b[105],x,c[105];
int main()
{
cin>>t;
int ans=1e7;
for (int i=1;i<=t;i++)
{
cin>>n;
for (int j=1;j<=n;j++) cin>>a[j];
sort(a+1,a+n+1);
for (int j=1;j<n;j++)
{
b[j]=abs(a[j]-a[j+1]);
//if (b[i]==0) b[i]=1e7;
}
sort(b+1,b+n);
for (int j=1;j<n;j++)
{
//cout<<b[j]<<" ";
//if (b[j]!=0 && b[j+1]!=0)
//ans=min(__gcd(b[j],b[j+1]),ans);
if (b[j]!=0) c[++x]=b[j];
}
//cout<<x<<endl;
if (x==0)
{
cout<<"-1"<<endl;
x=0;
continue;
}
if (x>=2)
{
for (int j=1;j<x;j++) ans=min(__gcd(c[j],c[j+1]),ans);
}
else
{
cout<<c[x]<<endl;
x=0;
continue;
}
cout<<ans<<endl;
ans=1e7;
x=0;
}
}