图论3 1011
三角形
有一个等边三角形,在每条边上等距离画n个点,(顶点上不画,把每条边分成n+1段),在这3n个点中选取3个点作为新三角形的顶点,求所有不同三角形的面积和。
3n个点有各自的编号,两个三角形不同当且仅当选取编号集合不同,规定单位面积为边长每一段长度的等边三角形面积。
答案对1e9+7取模
1<=n<=1e9
题解
很容易分出两类:有两个点在同一边上,三点都在不同边。
1.记有两个点的边为底边。可以得到
$2*3\sum_{x=1}^{n-1}x(n-x)*\sum_{h=1}^{n}h$(顶点可以在两边选取,底边有三种
$3n(n+1)(n\sum_{x=1}^{n-1}x-\sum_{x=1}^{n-1}x^{2})$
$\frac{n^{2}(n+1)(n^{2}-1)}{2}$
2.在三边分别选边,记a,b,c为三点到所在边的左端点的距离
$\sum_{a=1}^{n}\sum_{b=1}^{n}\sum_{c=1}^{n}(n+1)^{2}-(n+1-a)b-(n+1-b)c-(n+1-c)a$
$\sum_{a=1}^{n}\sum_{b=1}^{n}\sum_{c=1}^{n}(n+1)^{2}-(n+1)(a+b+c)+ab+ac+bc$
$(n+1)^{2}$与a,b,c无关,所以可以算得贡献为$n^{3}(n+1){2}$
对于(a+b+c)可以考虑画出树形图,发现c从1-n的取值重复了$n^{2}$次,所以贡献为$\frac{n^{3}(n+1)^{2}}{2}$,a,b,c并无本质区别,所以a+b+c的贡献为$\frac{3n^{3}(n+1)^{2}}{2}$
对于后面剩下的部分只看$(a+b)c$
$(\sum_{a=1}^{n}\sum_{b=1}^{n}(a+b))*\sum_{c=1}^{n}c$
$\frac{n^{3}(n+1)^{2}}{2}$
对于$ab$可以用$\sum_{c=1}^{n}(\sum_{a=1}^{n}a*\sum_{b=1}^{n}b)$计算或者可以根据a,b,c无本质区别直接对刚才的$(a+b)c$*3/2即可
最后合并就是$\frac{n^{2}(n+1)(n^{2}-1)}{2}+\frac{n^{3}(n+1)^{2}}{4}$
#include<cstdio> #include<iostream> #include<algorithm> #define ll long long using namespace std; const int mod=1000000007; const ll inv2=500000004; const ll inv4=250000002; ll n; ll ret=0,ans; int main(){ freopen("triangle.in","r",stdin); freopen("triangle.out","w",stdout); scanf("%lld",&n); ans=n*n%mod*(n+1)%mod*(n*n%mod-1)%mod*inv2%mod;//有两个点在一条边 ans=(ans+n*n%mod*n%mod*(n+1)%mod*(n+1)%mod*inv4%mod)%mod; printf("%lld",(ans%mod+mod)%mod); }
速度限制
题解
考虑到v很小而且通过道路时间和速度有关,所以直接把dis多开一维记录到达i点速度为j的时候的最小时间。
在最短路时,记录标点号和速度即可。可以看做分层图(按速度分层)。要求路径就直接记录前驱。
代码挺简单,但是一开始没想到方法...
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=155; const int maxm=555; const double inf=40000000000000000L; int n,m,t; int cnt,head[maxn]; double dis[maxn][maxm]; pair<int,int> pre[maxn][maxm]; int top,s[maxn]; struct edge{ int x,y,v,l,next; }e[maxn*maxn]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x = f ? -x : x ; } void add(int x,int y,int v,int l){ e[++cnt]=(edge){x,y,v,l,head[x]}; head[x]=cnt; } bool vis[maxn][maxm]; void spfa(){ queue<pair<int,int> > q; memset(dis,0x7f,sizeof(dis)); q.push(make_pair(0,70)); vis[0][70]=true;dis[0][70]=0; while(!q.empty()){ int x=q.front().first,nowv=q.front().second; q.pop(); vis[x][nowv]=false; for(int i=head[x];i;i=e[i].next){ int y=e[i].y; if(!e[i].v){//没限速 if(dis[y][nowv]>dis[x][nowv]+1.0*e[i].l/nowv){ dis[y][nowv]=dis[x][nowv]+1.0*e[i].l/nowv; pre[y][nowv]=make_pair(x,nowv); if(!vis[y][nowv]){ q.push(make_pair(y,nowv)); vis[y][nowv]=true; } } } else {//限速 if(dis[y][e[i].v]>dis[x][nowv]+1.0*e[i].l/e[i].v){ dis[y][e[i].v]=dis[x][nowv]+1.0*e[i].l/e[i].v; pre[y][e[i].v]=make_pair(x,nowv); if(!vis[y][e[i].v]){ q.push(make_pair(y,e[i].v)); vis[y][e[i].v]=true; } } } } } } int main(){ freopen("speed.in","r",stdin); freopen("speed.out","w",stdout); read(n);read(m);read(t); for(int i=1;i<=m;i++){ int x,y,v,l; read(x);read(y);read(v);read(l); add(x,y,v,l); } spfa(); pair<int,int> x=make_pair(t,0); double mx=inf; for(int i=0;i<=500;i++) if(dis[t][i]<mx) mx=dis[t][i],x.second=i; while(1){ s[++top]=x.first; if(!x.first) break; x=pre[x.first][x.second]; } for(int i=top;i;i--) printf("%d ",s[i]); }
替换游戏
题解
对于60%的数据,直接建返图缩点跑拓扑就好了
#include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=100005; int n,m,k,Q; int cnt,head[maxn]; int d[maxn]; vector<int> g[maxn]; int cur,dfn[maxn],low[maxn]; bool flag[maxn]; int top,s[maxn]; int num,res[maxn],size[maxn]; struct edge{ int x,y,next; }e[maxn<<3]; ll f[maxn]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x = f ? -x : x ; } void add(int x,int y){ e[++cnt]=(edge){x,y,head[x]}; head[x]=cnt;d[y]++; } void tarjan(int x){ dfn[x]=low[x]=++cur; flag[x]=true;s[++top]=x; for(unsigned int i=0;i<g[x].size();i++){ int y=g[x][i]; if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);} else if(flag[y]) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]){ ++num; int t; do{ t=s[top--]; res[t]=num; flag[t]=false; size[num]+=t; }while(t!=x); } } void topsort(){ queue<int> q; for(int i=1;i<=num;i++) if(!d[i]) q.push(i),f[i]=size[i]; while(!q.empty()){ int x=q.front(); q.pop(); for(int i=head[x];i;i=e[i].next){ int y=e[i].y; if(f[y]<f[x]+size[y]) f[y]=f[x]+size[y]; d[y]--; if(!d[y]) q.push(y); } } } void plana(){ for(int i=1;i<=m;i++){ int x,y; read(x);read(y); g[y].push_back(x); } for(int i=n;i>=k;i--) g[i].push_back(i-k); for(int i=0;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=0;i<=n;i++) for(unsigned int j=0;j<g[i].size();j++) if(res[i]!=res[g[i][j]]) add(res[i],res[g[i][j]]); topsort(); read(Q); while(Q--){ int x;read(x); printf("%lld\n",f[res[x]]); } } int main(){ freopen("substitution.in","r",stdin); freopen("substitution.out","w",stdout); read(n);read(m);read(k); plana(); } /* 11 3 12 1 10 10 1 11 10 */