标签:题目 end namespace print mod name lld 暴力求解 for
中间咕的几次考试就先咕着吧……
枚举斜率。只考虑斜率为正且不平行于坐标轴的直线,最后把$ans\times 2$再$+1$即可。
首先肯定需要用$gcd(i,j)==1$确保斜率的唯一性,但由于题目中Deadline的定义是直线不是线段,所以一个方向只能有一条,需要去重。那么我们计算一条直线的贡献,当且仅当它和它的前驱线段在点阵内且后继线段不在点阵内。
暴力求解:$ans=\sum \limits_{i=1}^{n-1} \sum \limits_{j=1}^{m-1} [gcd(i,j)==1] ((n-i)\times(m-j)-\max (n-2i,0) \times \max (m-2j,0))$,时间复杂度$O(n^2 T)$。
尝试通过预处理降低每次询问的复杂度:计算对于每个$i$与它互质的$j$的前缀个数与前缀和,之后把柿子拆一下复杂度就变成$O(nT)$的了。
卡内存?值域不超过4000的数组为什么不用short呢?(滑稽
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int mod=(1<<30),N=4005; typedef long long ll; int n,m,T; int sum[N][N]; short gcd[N][N],copr[N][N]; void work() { scanf("%d%d",&n,&m); ll ans=0; for(int i=1;i<=n-1;i++) { ll num1=1LL*(n-i)*(1LL*copr[i][m-1]*m-sum[i][m-1])%mod; if(n-2*i>0)num1=(num1-1LL*(n-2*i)*(1LL*m*copr[i][m/2]-2*sum[i][m/2])+mod)%mod; ans+=num1,ans%=mod; } /*for(int i=1;i<=n-1;i++) for(int j=1;j<=m-1;j++) if(gcd(i,j)==1)ans+=(1LL*(n-i)*(m-j)-max(n-i*2,0LL)*max(m-j*2,0LL));*/ printf("%lld\n",(ans*2%mod+1LL*n+m)%mod); } int main() { scanf("%d",&T); gcd[1][1]=gcd[1][2]=gcd[2][1]=1; for(int i=1;i<=4000;i++) gcd[i][0]=i,gcd[i][1]=gcd[1][i]=1; for(int i=1;i<=4000;i++) { for(int j=1;j<=4000;j++) { gcd[i][j]=gcd[min(i,j)][max(i,j)%min(i,j)]; copr[i][j]=copr[i][j-1],sum[i][j]=sum[i][j-1]; if(gcd[i][j]==1)copr[i][j]++,sum[i][j]+=j; //if(i<=50&&j<=50)cout<<i<<‘ ‘<<j<<‘ ‘<<gcd[i][j]<<‘ ‘<<copr[i][j]<<‘ ‘<<sum[i][j]<<endl; } } while(T--)work(); return 0; }
标签:题目 end namespace print mod name lld 暴力求解 for
原文地址:https://www.cnblogs.com/Rorschach-XR/p/11494472.html