T1
题目大意:我们有一个图和一些有向边,要求补无数条边使得其满足以下条件:1)i能到之后的所有点;2)边的终点比起点大;3)两点间最多一条边;4)如果j-i<=k,i到j的最短距离为j-i;5)如果j-i>k,i到j的最短距离为j-i或者j-i-k;
思路:考试的时候没有想出正解,不过想到了i只能向i+1或i+k+1连边,但是没有深入的展开。其实读完题目,应该得到的信息有:1)一定有i~i+1这条边,保证要求中的1);2)对于一个点,只能在向i+k+1连边;3)我们连的边一定在一个长度为k+1的区间内,否则就不满足最短距离的要求了,也就是所有的i~i+k+1的边都是相交的。然后就是进行穷举,找到所有可行的区间。
不过要注意以下问题:1)读入的时候如果一条边不满足j-i==1||j-i==k+1的条件,就要无解;2)如果读入的i~i+k+1的边中,有不相交的,也无解;3)在增加答案的时候,只增加之前没有的,也就是说,我们每次都要有一条之前没用过的新边,因为按起点区间的右端点枚举的,所以每一个区间的右端点一定没用过,一定要用到,所有就有了程序中注释的地方的神奇写法。
#include<iostream> #include<cstdio> #define p 1000000007LL using namespace std; int mi[1000001]={0},sum[1000001]={0},s[1000001]={0},e[1000001]={0}; int main() { freopen("olya.in","r",stdin); freopen("olya.out","w",stdout); int i,j,n,m,k,st,en,ans=0,mst,men; bool f; f=true;mi[0]=1;mst=0;men=1000001; for (i=1;i<=1000000;++i) mi[i]=(mi[i-1]<<1)%p; scanf("%d%d%d",&n,&m,&k); for (i=1;i<=m;++i) { scanf("%d%d",&st,&en); if (en-st!=1&&en-st!=k+1) { f=false;break; } if (en-st==k+1) { mst=max(st,mst);men=min(men,en); s[st]=1;e[en]=1; } } for (i=1;i<=n;++i) sum[i]=sum[i-1]+s[i]; if (mst>=men) f=false; if (f) { if (n<=k+1) ans=1; else { ans=1; for (j=max(1,mst);j<=n-k-1;++j) { if (e[j]) break; i=max(1,j-k); ans=(ans+mi[j-i-(sum[j-1]-sum[i-1])]-s[j])%p;//一定要选至少一条新边,所以我们一定要选j为起点的边, //但如果本来就有以j为起点的边,那么我们就把只选j的删去。 if (j-k+1>0&&s[j-k+1]>0) break; } } } if (!f) printf("0\n"); else printf("%d\n",ans); fclose(stdin); fclose(stdout); }
T2
题目大意:一个神奇的矩阵,然后某个子矩阵中元素的和。
(矩阵如下(只列举前16个元素):1 2 5 10
4 3 6 11
9 8 7 12
16 15 14 13 )
思路:考试的时候,只想了60分算法,就是穷举给定矩阵的列,然后根据各种神奇的求和公式求出这一列的和,然后相加。但是,宏定义中没有在1000000007后加LL,导致。(bei)。(ju)。(le)。满分算法其实用到了很简单的思路,用四个以(1,1)为左上角的矩形的和表示这个给定的矩形,而每个以(1,1)为左上角的矩形都可以表示为一个正方形(1~n^2)和一个矩形,这个矩形又很有特点(各种等差。。。),这样我们的o(1)算法就诞生了,各种神奇的公式。可能用到高精度,来处理过大的问题,不过貌似long double也可以。。。
(比较。。。所以就没有写满分的,放个60分的。。。)
#include<iostream> #include<cstdio> #include<cstring> #define ri 10000000000LL using namespace std; long long fh[10001]={0},f[10001]={0},shu[100]={0}; int main() { freopen("matrix.in","r",stdin); freopen("matrix.out","w",stdout); int x1,y1,x2,y2,t,i,j,z; long long ans,xx; for (i=1;i<=10000;++i) { f[i]=i*i; fh[i]=fh[i-1]+f[i]; } scanf("%d",&t); while(t) { ans=0; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); for (i=y1;i<=y2;++i) { if (x2<=i) { ans+=(x2-x1+1)*(2*f[i-1]+x1+x2)/2; } else { if (x1<=i) { z=x2-i; xx=(long long)z; ans+=((2*f[i-1]+(x1+i))*(i-x1+1)/2+xx*f[i-1]+xx*i+(1+xx)*xx*i+fh[z]); } else { z=x2-x1+1; xx=(long long)z; ans+=xx*f[i-1]+xx*i+(x1-i+x2-i)*xx*i+fh[x2-i]-fh[x1-i-1]; } } } if (ans/ri>0) { printf("..."); ans%=ri; memset(shu,0,sizeof(shu));j=0; while(ans) { ++j;shu[j]=ans%10; ans/=10; } for (i=10;i>=1;--i) printf("%I64d",shu[i]); printf("\n"); } else printf("%I64d\n",ans); --t; } fclose(stdin); fclose(stdout); }