有几天没有写总结了,后面应该会补上之前的总结。
第一次全场爆零呵呵呵呵。。。。。。。。。
第一题错在了最后答案没有%mod再输出(最好从头到尾都%mod);
第二题大概是没有很好地把握时间复杂度;
第三题嘛。。我是真的不知道怎么WA了,大概是爆int了?
上题。
1.数列求和
理解题意并不难,就是将原数列的每一个子段内部相乘,每一个子段之间将相乘的积相加。不难看出(所以这里真的不难看出吗。。。为什么我就是没有看出。。。),考虑所有右端点为x的答案,可以发现答案为所有右端点为x-1的答案加1,再乘a。但是由于后面到了1e18的精度,所以用快速乘即可。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
int n;
long long p,ans,now;
long long x;
inline long long read()
{
long long i=0;char c;
for(c=getchar();c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())
i=(i<<1)+(i<<3)+c-'0';
return i;
}
inline long long ksc(long long x,long long y)
{
long long ans=0,aa=x;
while(y) //快速乘。
{
if(y&1)
ans=(ans+aa)%p;
aa=(aa+aa)%p,y>>=1;
}
return ans;
}
int main()
{
//freopen("sum.in","r",stdin);
//freopen("sum.out","w",stdout);
n=read(),p=read();
ans=0;now=0;
for(int i=1;i<=n;i++)
{
x=read();
now=ksc(now+1,x);
ans=(ans+now)%p;
}
printf("%lld\n",ans);
return 0;
}
2.路径统计
可以看出,每一个连通块里面,都是一个环再加上环上的许许多多奇形怪状的树,不同的连通块则不能连通。环上点对答案的贡献很好写,然后就是树边,下方的子树与上方路径上的点和环上点的路径。
要缩点呐,dfs其实就是dijkstra的思想。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<vector>
using namespace std;
struct node
{
int next,to,w;
}bian[500010];
const int p=1000000007;
int n,tot,cnt,num,top,idx;
int first[500010],len[500010],t[500010];
int dfn[500010],low[500010],stk[500010];
int id[500010],size[500010],dis[500010];
long long sum[500010],val[500010],ans;
bool flag[500010];
vector<int>f[500010];
inline int read()
{
int i=0;char c;
for(c=getchar();c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())
i=(i<<1)+(i<<3)+c-'0';
return i;
}
inline void add(int x,int y,int z)
{
bian[++tot].next=first[x];
first[x]=tot;
bian[tot].to=y;
bian[tot].w=z;
}
inline void tarjan(int u)
{
dfn[u]=low[u]=++idx;
stk[++top]=u;flag[u]=true;
int v=t[u];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else
if(flag[v])
low[u]=min(low[u],dfn[v]);
if(low[u]==dfn[u])
{
++num;
v=stk[top];
while(u!=v)
{
id[v]=num;size[num]++;
f[num].push_back(v);
top--;flag[v]=false;
v=stk[top];
}
id[v]=num;size[num]++;
f[num].push_back(v);
top--;flag[v]=false;
}
}
inline void dfs(int u,int cnt)
{
flag[u]=true;
ans=((ans-1ll*(n-cnt)*size[u])%p)%p;
for(int i=first[u];i;i=bian[i].next)
{
int v=bian[i].to;
if(!flag[v])
dfs(v,cnt+size[v]);
ans=(ans+1ll*size[v]*cnt%p*bian[i].w%p)%p;
size[u]+=size[v];
}
}
inline void zql(int i)
{
int u;
reverse(f[i].begin(),f[i].end());
for(int j=0;j<size[i];j++)
u=f[i][j],val[f[i][0]]=(val[f[i][0]]+1ll*(size[i]-j)*len[f[i][j]]%p)%p;
for(int j=1;j<size[i];j++)
u=f[i][j],val[f[i][j]]=(val[f[i][j-1]]+sum[i]-1ll*size[i]%p*len[f[i][j-1]]%p)%p;
for(int j=0;j<size[i];j++)
u=f[i][j],val[f[i][j]]=(val[f[i][j]]-sum[i])%p;
}
int main()
{
//freopen("road.in","r",stdin);
//freopen("road.out","w",stdout);
int _q=50<<20;
char *_p=(char*)malloc(_q)+_q;
__asm__("movl %0, %%esp\n"::"r"(_p)); //改变栈空间的大小。
n=read();
for(int i=1;i<=n;i++)
t[i]=read(),len[i]=read();
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
if(id[i]==id[t[i]])
sum[id[i]]=(sum[id[i]]+len[i])%p;
else
add(id[t[i]],id[i],len[i]);
for(int i=1;i<=num;i++)
{
if(size[i]==1) continue;
ans=(ans+1ll*size[i]*(size[i]-1)/2%p*sum[i]%p)%p;
zql(i);
}
memset(flag,0,sizeof(flag));
for(int i=1;i<=num;i++)
if(!flag[i])
dfs(i,size[i]);
for(int i=1;i<=n;i++)
if(id[i]!=id[t[i]])
ans=(ans+1ll*size[id[i]]*val[t[i]]%p)%p;
cout<<(ans%p+p)%p;
return 0;
}
3.小店购物
唔说实话感觉这道题还要比上一道题简单一些。
看完题就会发现,需要一个数据结构能够支持单点修改,区间最值查询的,用线段树就好了。然而为了减少复杂度,需要离散化。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
using namespace std;
struct node1
{
long long p,w;
int num,t;
}wu[2000010];
struct node2
{
int k;
long long x,y,z;
}qu[1000010];
const long long inf=1E+17;
int n,m,tot,bz;
int to[2000010],f[2000010];
long long tree[2000010];
inline bool comp(const node1 &a,const node1 &b)
{
if(a.w==b.w)
return a.p<b.p;
return a.w>b.w;
}
inline void build(int root,int l,int r)
{
if(l==r)
{
if(!wu[l].t)
tree[root]=wu[l].p;
else
tree[root]=inf;
return;
}
int mid=(l+r)/2;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
tree[root]=min(tree[root*2],tree[root*2+1]);
}
inline void que(int root,int l,int r,int t)
{
if(l==r)
{
bz=l;return;
}
int mid=(l+r)/2;
if(tree[root*2]<=t)
que(root*2,l,mid,t);
else if(tree[root*2+1]<=t)
que(root*2+1,mid+1,r,t);
}
inline void zql(int root,int l,int r,int t)
{
if(l==r)
{
if(t==l)
tree[root]=inf;
return;
}
int mid=(l+r)/2;
if(t<=mid)
zql(root*2,l,mid,t);
else
zql(root*2+1,mid+1,r,t);
tree[root]=min(tree[root*2],tree[root*2+1]);
}
inline void czh(int root,int l,int r,int t)
{
if(l==r)
{
if(t==l)
tree[root]=wu[l].p;
return;
}
int mid=(l+r)/2;
if(t<=mid)
czh(root*2,l,mid,t);
else
czh(root*2+1,mid+1,r,t);
tree[root]=min(tree[root*2],tree[root*2+1]);
}
int main()
{
//freopen("shopping.in","r",stdin);
//freopen("shopping.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>wu[++tot].w;
cin>>wu[tot].p;
wu[tot].num=i;
}
for(int i=1;i<=m;i++)
{
cin>>qu[i].k;
if(qu[i].k==2)
cin>>qu[i].x;
else
{
cin>>qu[i].x>>qu[i].y>>qu[i].z;
wu[++tot].w=qu[i].y;
wu[tot].p=qu[i].z;
wu[tot].num=qu[i].x;
wu[tot].t=i;
}
}
sort(wu+1,wu+tot+1,comp);
for(int i=1;i<=tot;i++)
to[wu[i].t]=i;
for(int i=1;i<=tot;i++)
if(!wu[i].t)
f[wu[i].num]=i;
build(1,1,tot);
for(int i=1;i<=m;i++)
{
if(qu[i].k==2)
{
long long ans=0;
while(qu[i].x>=tree[1])
{
que(1,1,tot,qu[i].x);
ans+=qu[i].x/wu[bz].p*wu[bz].w;
qu[i].x-=qu[i].x/wu[bz].p*wu[bz].p;
}
cout<<ans<<"\n";
}
else
{
zql(1,1,tot,f[qu[i].x]);
czh(1,1,tot,to[i]);
f[qu[i].x]=to[i];
}
}
return 0;
}
以上。
来自2017.11.8.
——我认为 return 0,是一个时代的终结。