noip模拟38[这怕不是1/4???]
noip模拟38 solutions
我觉得吧,这次考试还是非常的容易,因为之前的[x,y,z][u,v,w]给我吓到了
所以我差点考场就切掉一个题,第二题属实是真的傻了
所以这一场除了最后一题难改,别的都挺简单的。
T1 a
简单来说就是一个双指针,就完事了
因为在每一行上,你左上端点的移动会导致右下端点的单调右移。
所以我们直接对每一行开两个指针,扫就行了
0的情况,只能特判,好像双指针不太行了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const int N=35;
const int M=5e4+5;
int n,m,l,r;
int jz[N][M],fro[N][M];
int pol[N],por[N];
ll ans;
signed main(){
//cout<<"a"<<endl;
scanf("%d%d",&n,&m);
for(re i=1;i<=n;i++){
char x[M];
scanf("%s",x+1);
for(re j=1;j<=m;j++){
jz[i][j]=x[j]-'0';
fro[i][j]=fro[i-1][j]+fro[i][j-1]-fro[i-1][j-1]+jz[i][j];
}
}
scanf("%d%d",&l,&r);
if(l==0&&r==n*m){
for(re i=1;i<=n;i++){
for(re j=1;j<=m;j++){
ans+=1ll*(n-i+1)*(m-j+1);
}
}
printf("%lld",ans);
return 0;
}
for(re i=0;i<n;i++){
memset(pol,0,sizeof(pol));
memset(por,0,sizeof(por));
for(re j=0;j<m;j++){
for(re x=i+1;x<=n;x++){
for(re y=pol[x];y<=m;y++){
if(fro[x][y]-fro[x][j]-fro[i][y]+fro[i][j]>=l){
pol[x]=y;break;
}
if(y==m)pol[x]=m+1;
}
for(re y=por[x]+1;y<=m;y++){
if(fro[x][y]-fro[x][j]-fro[i][y]+fro[i][j]>r){
por[x]=y-1;break;
}
if(y==m)por[x]=m;
}
if(pol[x]!=m+1)ans+=por[x]-pol[x]+1;
}
}
}
printf("%lld",ans);
}
T2 b
值域这么小!!!你竟然想不到要枚举值域????
确实我考场上就没有想到,
我们直接暴力容斥,就像题解上说的那样
时间复杂度我还是要证明一下
\(1+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{n}=\ln{n}\)
这个就是调和级数,无穷级数的一种
我们还要枚举每一个n,所以总的时间复杂度就是\(\mathcal{O(n\ln{n})}\)
其实我们容斥的过程还可以用莫比乌斯反演来解释
如果有 \(f(n)=\sum_{n|d}g(d)\),那么有 \(g(n)=\sum_{n|d}\mu(\frac{d}{n})f(d)\)
直接得到对应的数量
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
const ll mod=1e9+7;
const int N=25;
const int M=1e5+5;
int n,m,c[N][M],cnt[N][M];
ll ans,sum[M],maxn;
ll ksm(ll x,ll y){
ll ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;
y>>=1;
}
return ret;
}
signed main(){
scanf("%d%d",&n,&m);
for(re i=1;i<=n;i++)
for(re j=1;j<=m;j++){
ll a;scanf("%lld",&a);
c[i][a]++;maxn=max(maxn,a);
}
for(re i=1;i<=n;i++)
for(re j=1;j<=maxn;j++)
for(re k=1;k*j<=maxn;k++)
cnt[i][j]+=c[i][j*k];
for(re j=maxn;j>=1;j--){
sum[j]=1;
for(re i=1;i<=n;i++)
sum[j]=1ll*sum[j]*(cnt[i][j]+1)%mod;
sum[j]=(sum[j]-1+mod)%mod;
if(!sum[j])continue;
for(re k=2;k*j<=maxn;k++)
sum[j]=(sum[j]-sum[k*j]+mod)%mod;
ans=(ans+sum[j]*j%mod)%mod;
}
printf("%lld",ans);
}
T3 c
话说这个题让我对点分治的理解又一步加深了,
原来还可以用来做dp
话说为啥只需要三个颜色就够了??因为我们之关心当前的颜色和两侧的关系
那么在多出一条不一样的就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=1e5+5;
const int M=3e5+5;
int n,m,q;
vector<pair<int,int> > edg[N];
vector<pair<int,vector<int> > > g[N];
vector<int> vfa[N];
int dp[N][3][3];
struct QUS{
int x,y,id;
QUS(){}
QUS(int a,int b,int c){
x=a;y=b;id=c;
}
};
vector<QUS> qus[N];
int ans[N];
void dfs_unique(int x,int f){
sort(edg[x].begin(),edg[x].end());
edg[x].erase(unique(edg[x].begin(),edg[x].end()),edg[x].end());
for(re i=0,j;i<edg[x].size();i=j){
int y=edg[x][i].first;j=i+1;
while(edg[x][j].first==y&&j<edg[x].size())j++;
if(y==f)continue;
g[x].push_back(make_pair(y,vector<int>()));
g[y].push_back(make_pair(x,vector<int>()));
for(re k=i;k<j&&k<i+3;k++){
g[x].back().second.push_back(edg[x][k].second);
g[y].back().second.push_back(edg[x][k].second);
}
dfs_unique(y,x);
}
}
bool vis[N];
int ms[N],siz[N],rt;
void get_rt(int x,int f,int tot){
siz[x]=1;ms[x]=0;
for(re i=0,y;i<g[x].size();i++){
y=g[x][i].first;
if(vis[y]||y==f)continue;
get_rt(y,x,tot);
siz[x]+=siz[y];
ms[x]=max(ms[x],siz[y]);
}
ms[x]=max(ms[x],tot-siz[x]);
if(ms[x]<=tot/2)rt=x;
}
int sfa[N][21],sdep[N];
void pre_sol(int x,int tot,int f){
get_rt(x,0,tot);x=rt;
//cout<<x<<" "<<f<<endl;
vis[x]=true;
sfa[x][0]=f;
sdep[x]=sdep[sfa[x][0]]+1;
//cout<<x<<" "<<sdep[x]<<endl;
for(re i=1;i<=20;i++)sfa[x][i]=sfa[sfa[x][i-1]][i-1];
for(re i=0,y;i<g[x].size();i++){
y=g[x][i].first;
if(vis[y]||y==f)continue;
//get_siz(y,x);
if(siz[y]<=siz[x])pre_sol(y,siz[y],x);
else pre_sol(y,tot-siz[x],x);
}
}
inline int LCA(int x,int y){
//cout<<x<<" "<<y<<" "<<sdep[x]<<" "<<sdep[y]<<endl;
if(sdep[x]<sdep[y])swap(x,y);
for(re i=20;i>=0;i--){
if(sdep[sfa[x][i]]>=sdep[y])
x=sfa[x][i];
}
//cout<<x<<" "<<y<<" "<<endl;
if(x==y)return x;
for(re i=20;i>=0;i--){
if(sfa[x][i]!=sfa[y][i])
x=sfa[x][i],y=sfa[y][i];
}
return sfa[x][0];
}
int tmp[N];
void dfs_dp(int x,int f,int rt){
tmp[x]=rt;
for(re i=0,y;i<g[x].size();i++){
y=g[x][i].first;
if(vis[y]||y==f)continue;
vfa[y]=g[x][i].second;
for(re j=0;j<vfa[rt].size();j++){
for(re k=0;k<vfa[y].size();k++){
dp[y][j][k]=-1e9;
for(re o=0;o<vfa[x].size();o++)
dp[y][j][k]=max(dp[y][j][k],dp[x][j][o]+(vfa[x][o]!=vfa[y][k]));
}
}
dfs_dp(y,x,rt);
}
}
void get_ans(int x,int tot){
get_rt(x,0,tot);x=rt;
vis[x]=true;
for(re i=0,y;i<g[x].size();i++){
y=g[x][i].first;
if(vis[y])continue;
vfa[y]=g[x][i].second;
for(re j=0;j<vfa[y].size();j++){
for(re k=0;k<vfa[y].size();k++){
if(j==k)dp[y][j][k]=1;
else dp[y][j][k]=-1e9;
}
}
dfs_dp(y,x,y);
}
for(re i=0,a,b;i<qus[x].size();i++){
a=qus[x][i].x;b=qus[x][i].y;
//cout<<a<<" "<<b<<endl;
if(b==x)swap(a,b);
if(a==b)ans[qus[x][i].id]=0;
else if(a==x)
for(re j=0;j<vfa[tmp[b]].size();j++)
for(re k=0;k<vfa[b].size();k++)
ans[qus[x][i].id]=max(ans[qus[x][i].id],dp[b][j][k]);
else {
for(re j=0;j<vfa[tmp[a]].size();j++)
for(re k=0;k<vfa[a].size();k++)
for(re p=0;p<vfa[tmp[b]].size();p++)
for(re q=0;q<vfa[b].size();q++)
ans[qus[x][i].id]=max(ans[qus[x][i].id],dp[a][j][k]+dp[b][p][q]-(vfa[tmp[a]][j]==vfa[tmp[b]][p]));
}
}
for(re i=0,y;i<g[x].size();i++){
y=g[x][i].first;
if(vis[y])continue;
//get_siz(y,x);
if(siz[y]<=siz[x])get_ans(y,siz[y]);
else get_ans(y,tot-siz[x]);
}
}
signed main(){
scanf("%d%d",&n,&m);
for(re i=1;i<=m;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
edg[x].push_back(make_pair(y,z));
edg[y].push_back(make_pair(x,z));
}
dfs_unique(1,0);
pre_sol(1,n,0);
scanf("%d",&q);
for(re i=1;i<=q;i++){
int x,y;scanf("%d%d",&x,&y);
//cout<<LCA(x,y)<<endl;
qus[LCA(x,y)].push_back(QUS(x,y,i));
}
memset(vis,false,sizeof(vis));
get_ans(1,n);
for(re i=1;i<=q;i++)printf("%d\n",ans[i]);
}
话说最重要的就是vis数组,T飞了
QQ:2953174821