今天的题目顺序有点小坑,第一题是难度最大的一题!很多同学都和我一样硬钢,然后时间就这样逝去的。
从难度大的开始分析吧。
T5.dp+矩阵快速幂。
我们设d[i]为以d[i]为深度的满足条件的点,也就是答案。
可以得出d[i]=
这个是很显然的,因为每一个点都可以转化为其他点到达。
但是看数据的范围,知道这样肯定会T掉,于是我们就需要矩阵快速幂的优化。怎么优化呢?我讲不清楚,于是就截了一张大神的图,orz~
我来分析一下吧,B数组的若干个1和0,其实是取到保留位的作用,因为只有1出现的位置,才对A数组有功效。其实他的图并不全,因为我们要加上根节点的1,所以我们还要开辟一列,在b[101][1],b[101][101]设为1,这样才会保留1,才能进行矩阵幂。
说一下代码实现的细节吧,矩阵快速幂模板一写,然后要注意边界的问题,我们要用两个变量分别记录a,b数组的边界,然后跑*运算不要越界就可以了。
T4.线段树+二分
我们建造5颗维护最值的线段树,然后二分区间的长度,枚举起点,注意不要越界,然后就可以轻松解决了,但是我是线段树小白,发现线段树都不会写,折磨了好久。。以后还要学学。(老师说了一种运用单调队列的方法,orz)
T3.哈希 就是修改一个字符串的每个节点,因为只有abc三个字符,枚举一遍。然后判断有没有重复。
T2.暴力出奇迹,比较任意两个点,算k。我写了另一种nlogn的算法,但是由于精度的问题,炸了。。
T1.就是模拟吧,判断每一个位上的字符和9-该位的字符的大小,然后就可以出来了。
PS:另更新一文为矩阵快速幂模板。
附上代码:
A
#include<bits/stdc++.h>
#define maxn 120
#define mod (1000000007)
#define LL long long
using namespace std;
LL n,k;
struct Node{
LL s[maxn][maxn];
int n,m;
}str;
Node operator * (Node a,Node b)
{
Node tmp;tmp.n=a.n;tmp.m=b.m;
LL x=0;
for(int i=1;i<=a.n;i++)
for(int j=1;j<=b.m;j++)
{
x=0;
for(int k=1;k<=a.m;k++)
x+=a.s[i][k]*b.s[k][j]%mod;
tmp.s[i][j]=x%mod;
}
return tmp;
}
int main()
{
cin>>n>>k;
Node a,b;a.n=1,a.m=101;b.n=b.m=101;
b.s[101][1]=b.s[101][101]=1;
a.s[1][1]=a.s[1][101]=1;
for(int i=2;i<=100;i++) b.s[i-1][i]=1;
for(int i=1;i<=n;i++)
{
int kk;
cin>>kk;b.s[kk][1]++;
}
while(k)
{
if(k&1) a=a*b;
b=b*b;
k>>=1;
}
cout<<a.s[1][1]<<endl;
return 0;
}
C
#include<bits/stdc++.h>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define maxn 500000
#define inf 12984020
using namespace std;
int n,m,k;
struct IntervalTree{
int Max[maxn];
int a[maxn];
void build(int l,int r,int rt)
{
if(l==r) {Max[rt]=a[l];return;}
int mid=l+(r-l)/2;
build(l,mid,ls),build(mid+1,r,rs);
Max[rt]=max(Max[ls],Max[rs]);
}
int query(int L,int R,int l,int r,int rt)
{
int amax=0;
if(L<=l&&r<=R) {amax=max(amax,Max[rt]);return amax;}
else
{
int lmax=0,rmax=0;
int mid=l+(r-l)/2;
if(L<=mid)lmax=max(lmax,query(L,R,l,mid,ls));
if(R>mid) rmax=max(rmax,query(L,R,mid+1,r,rs));
return amax=max(lmax,rmax);
}
}
void output(int l,int r,int rt)
{
if(l==r) return ;
cout<<l<<" "<<r<<" "<<Max[rt]<<endl;
int mid=l+(r-l)/2;
output(l,mid,ls),output(mid+1,r,rs);
}
}tree[8];
int sum[8],rans[8];
int erfen(int x)
{
if(x==0) return 1;
for(int i=1;i<=n-x+1;i++)
{
memset(sum,0,sizeof(sum));
int ans=0;
for(int j=1;j<=m;j++)
{
sum[j]=tree[j].query(i,i+x-1,1,n,1);
ans+=sum[j];
}
if(ans<=k)
{
for(int i=1;i<=m;i++)
rans[i]=sum[i];
return 1;
}
}
return 0;
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>tree[j].a[i];
for(int i=1;i<=m;i++)
tree[i].build(1,n,1);
int l=1,r=n;
while(l<=r)
{
int mid=l+(r-l)/2;
if(erfen(mid))
l=mid+1;
else r=mid-1;
}
for(int i=1;i<=m;i++)
cout<<rans[i]<<" ";
return 0;
}
这种结构体内套线段树真的好用!
E
#include<bits/stdc++.h>
#define mod 1000000000000000007
#define LL long long
using namespace std;
LL se[600100];
LL n,m;
set<LL> s;
inline LL hash(string str)
{
LL len=str.length();
LL ha=0;
for(LL i=0;i<len;i++)
ha+=(se[i]*(str[i]-'a'+1)%mod)%mod,ha%=mod;
return ha;
}
inline bool judge(string str)
{
LL ha=hash(str);
LL len=str.length();
for(LL j=0;j<len;j++)
{
LL num=str[j]-'a'+01;
for(LL i=1;i<=3;i++) if(i!=num)
{
LL haah=(ha-(num*se[j])%mod+(i*se[j])%mod+mod)%mod;
if(s.count(haah))
return 1;
}
}
return 0;
}
int main()
{
se[0]=1;
for(LL i=1;i<=600006;i++)
se[i]=(se[i-1]*4)%mod;
s.clear();
string str;
cin>>n>>m;
for(LL i=1;i<=n;i++)
{cin>>str;s.insert(hash(str));}
for(LL i=1;i<=m;i++)
{
cin>>str;
if(judge(str))
cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
D
#include<bits/stdc++.h>
#define maxn 2000
#define mod (1000000000+7)
using namespace std;
int n,k;
double sx,sy;
double x[maxn],y[maxn];
int book[maxn];
int ans=0;
int main()
{
cin>>n>>sx>>sy;
for(int i=1;i<=n;i++)
cin>>x[i]>>y[i];
for(int i=1;i<=n;i++)if(!book[i])
{
book[i]=1;ans++;
for(int j=i+1;j<=n;j++)
{
if(x[i]==sx&&x[j]==sx) book[j]=1;
else if((y[i]-sy)/(x[i]-sx)==(y[j]-sy)/(x[j]-sx)) book[j]=1;
}
}
cout<<ans<<endl;
return 0;
}
/*
4 0 0
10000 9999
9999 9998
-10000 -9999
-9999 -9998
*/
下面是我yy出来的坑数据
B
#include<bits/stdc++.h>
using namespace std;
long long n;
int s[2000];
int cnt=0;
int main()
{
cin>>n;
while(n>=1)
s[++cnt]=n%10,n/=10;
if(s[cnt]==9) cout<<'9';
else cout<<min(s[cnt],9-s[cnt]);
for(int i=cnt-1;i>=1;i--)
cout<<min(s[i],9-s[i]);
return 0;
}