d2也挺简单的,t1一个二维前缀和,t2一个bfs+spfa,t3难度较大,但是代码实现难度不大,而且30非常好拿。所以两天成绩=260+230=490,好菜啊qwq,往年的题都做成这个样子……
t1:无线网络发射器选址,又是一个模拟,只要处理下二维前缀和就好,注意判断好边界,不要让数组越界
#include#include #include #include using namespace std;int d,n,x,y,z,ans1,ans2,xa,xb,ya,yb,sum[130][130];//这个题我们只需要求个二维前缀和,再枚举中心就好了,注意处理好边界 int main(){ scanf("%d%d",&d,&n); for(int i=1;i<=n;i++) scanf("%d%d%d",&x,&y,&z),sum[x+1][y+1]+=z;//将范围转化成1-129 for(int i=1;i<=129;i++)//先求每一行一维前缀和 for(int j=2;j<=129;j++) sum[i][j]+=sum[i][j-1]; for(int i=1;i<=129;i++)//再一列列地叠加 for(int j=2;j<=129;j++) sum[j][i]+=sum[j-1][i]; for(int i=1;i<=129;i++) for(int j=1;j<=129;j++) { xa=max(i-d,1),xb=min(i+d,129);//注意要保证不越界 ya=max(j-d,1),yb=min(j+d,129); int qaq=sum[xb][yb]-sum[xb][ya-1]-sum[xa-1][yb]+sum[xa-1][ya-1];//求一块正方形内的答案,很简单就可以得到这个式子 if(ans2
t2:寻找道路,这个首先我们就可以想到反向建图,选出能够到达终点的点,然后在枚举它们,判断是否符合条件,符合就把与它相连的所有边建起来,这样并不会多出能到达终点的路径,因为会在半路中截断,建出图来就好办了,跑一边spfa就完事了
#include#include #include #include using namespace std;int n,m,ta1,ta2,ta3,x,y,s,e;struct in{ int to,ne;}ter[200020],es[200020],ing[200020];int he1[10010],ans[10010],he2[10010],he3[10010];bool flag[10010];inline void bu1(int f,int l){ ter[++ta1]=(in){l,he1[f]},he1[f]=ta1; es[++ta2]=(in){f,he2[l]},he2[l]=ta2;}queue qwq;inline void bfs(int fi){ qwq.push(fi),flag[fi]=1;//从终点出发,看能够到哪些点 while(!qwq.empty()) { int qaq=qwq.front(); qwq.pop(); for(int i=he2[qaq];i>0;i=es[i].ne) { int t=es[i].to; if(!flag[t])//这样就可以防止自环和重边导致死循,也可以记录出可到达终点的点 qwq.push(t),flag[t]=1; } }}inline void bu2(int f,int l){ ing[++ta3]=(in){l,he3[f]},he3[f]=ta3;}inline void init(){ bool fl=1; for(int i=1;i<=n;i++) { fl=1; if(flag[i])//如果这个点能够到达终点 { for(int j=he1[i];j>0;j=ter[j].ne) { int t=ter[j].to; if(!flag[t])//如果它的蛾子不能到达终点,不合题意,退出 { fl=0;break; } } if(fl)//如果它的蛾子能够到达终点就建边(就算后面有不能到达终点的后代也无所谓,因为这样不会建边) { for(int j=he1[i];j>0;j=ter[j].ne) bu2(i,ter[j].to); } } }}inline void spfa()//跑一边最短路 { memset(ans,0x7f,sizeof(ans)); memset(flag,0,sizeof(flag)); qwq.push(s),flag[s]=1,ans[s]=0; while(!qwq.empty()) { int qaq=qwq.front(); for(int i=he3[qaq];i>0;i=ing[i].ne) { int t=ing[i].to; if(ans[t]>ans[qaq]+1)//边权为1 { ans[t]=ans[qaq]+1; if(!flag[t]) qwq.push(t),flag[t]=1; } } flag[qaq]=0; qwq.pop(); } if(ans[e]<2139062143) cout<
t3:这是2014年最有难度的一个题,首先我们可以转化一下方程。
根据秦九韶算法:
所以我们可以简化一下计算,降低一下时间复杂度,这是第一个优化
之后我们想一下,如果我们将方程模上一个质数,这时如果满足另一边为0的时候,我们是不是可以基本看成x是方程的一个解,当然肯定会出现错误,但是如果我们多模上几个质数的时候,出错的概率就会大大降低呢?所以我们可以多模上几个数,这样也避免了高精运算2333333
#include#include #include #include using namespace std;typedef long long lo;const lo m1=99991;const lo m2=998244353;const lo m3=1000000007;lo n,m,a[110],b[110],c[110],ans,lin[1000010];bool flag[1000010];inline void re(int i){ char s=getchar(); bool fl=0; while(s<'0'||s>'9') { if(s=='-') fl=1; s=getchar(); } while(s>='0'&&s<='9')//取模是为了存的开 a[i]=((a[i]*10%m1)+s-'0')%m1,b[i]=((b[i]*10%m2)+s-'0')%m2,c[i]=((c[i]*10%m3)+s-'0')%m3,s=getchar(); if(fl) a[i]*=-1,b[i]*=-1,c[i]*=-1;}inline bool ask1(lo x){ lo su=0; for(lo i=n;i>=1;i--)//秦九韶的具体实现 su=((a[i]+su)*x)%m1; su=(su+a[0])%m1; if(su==0)//如果答案最后等于零,方程两边相等 return 1; return 0;}inline bool ask2(lo x){ lo su1=0,su2=0; for(lo i=n;i>=1;i--)//与上面类似,基本同理 su1=((b[i]+su1)*x)%m2,su2=((c[i]+su2)*x)%m3; su1=(su1+b[0])%m2,su2=(su2+c[0])%m3; if(su1==0&&su2==0) return 1; return 0;}int main(){ scanf("%lld%lld",&n,&m); for(int i=0;i<=n;i++) re(i); for(lo i=1;i<=m1;i++) { if(ask1(i))//如果在模99991意义下可以,才能进一步判断 { for(lo j=i;j<=m;j+=m1) { if(ask2(j))//如果另外两个质数下也可以才算是个答案 flag[j]=1; } } } for(lo i=1;i<=m;i++) if(flag[i]) lin[++ans]=i; cout< <<'\n'; for(lo i=1;i<=ans;i++) cout< <<'\n';}
抽空我再做15年的报告,毕竟15年的题还是很有难度的……