d2也挺简单的,t1一个二维前缀和,t2一个bfs+spfa,t3难度较大,但是代码实现难度不大,而且30非常好拿。所以两天成绩=260+230=490,好菜啊qwq,往年的题都做成这个样子……
t1:无线网络发射器选址,又是一个模拟,只要处理下二维前缀和就好,注意判断好边界,不要让数组越界
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> 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<qaq)//如果现在答案偏小,更新答案;如果答案与当前正方形答案相等,则次数+1 ans2=qaq,ans1=1; else if(ans2==qaq) ans1++; } cout<<ans1<<' '<<ans2; }
t2:寻找道路,这个首先我们就可以想到反向建图,选出能够到达终点的点,然后在枚举它们,判断是否符合条件,符合就把与它相连的所有边建起来,这样并不会多出能到达终点的路径,因为会在半路中截断,建出图来就好办了,跑一边spfa就完事了
#include<iostream> #include<cstring> #include<cstdio> #include<queue> 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<int>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<<ans[e]; else cout<<-1; } /* 这个题我们可以先反向建图,然后判断出哪些点可以到达终点 之后再根据题目要求,将自己蛾子所有能够直接或者间接到终点的点的所有边接起来 这样做并不会出现不符合题意的路径,因为所有不应该到达终点的路径就算多建了几条边,也会因为中间的点不满足条件而最后不会联通到终点 所以我们重新建了一张图,之后跑个spfa就可以了 */ int main() { memset(he1,-1,sizeof(he1)); memset(he2,-1,sizeof(he2)); memset(he3,-1,sizeof(he3)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&x,&y),bu1(x,y);//第一遍建图 scanf("%d%d",&s,&e); bfs(e);//先处理出有哪些点可以直接或者间接到终点 init();//第二遍建图 spfa();//跑最短路求答案 }
t3:这是2014年最有难度的一个题,首先我们可以转化一下方程。
根据秦九韶算法:
所以我们可以简化一下计算,降低一下时间复杂度,这是第一个优化
之后我们想一下,如果我们将方程模上一个质数,这时如果满足另一边为0的时候,我们是不是可以基本看成x是方程的一个解,当然肯定会出现错误,但是如果我们多模上几个质数的时候,出错的概率就会大大降低呢?所以我们可以多模上几个数,这样也避免了高精运算2333333
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> 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<<ans<<'\n'; for(lo i=1;i<=ans;i++) cout<<lin[i]<<'\n'; }
抽空我再做15年的报告,毕竟15年的题还是很有难度的……