HDU4944多校第七场第十题(请叫我事前猪一样。。。)

来源:互联网 发布:js跨域解决方案c# 编辑:程序博客网 时间:2024/06/10 03:00

FSF’s game

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 332    Accepted Submission(s): 157


Problem Description
FSF has programmed a game.
In this game, players need to divide a rectangle into several same squares.
The length and width of rectangles are integer, and of course the side length of squares are integer.

After division, players can get some coins.
If players successfully divide a AxB rectangle(length: A, width: B) into KxK squares(side length: K), they can get A*B/ gcd(A/K,B/K) gold coins.
In a level, you can’t get coins twice with same method.
(For example, You can get 6 coins from 2x2(A=2,B=2) rectangle. When K=1, A*B/gcd(A/K,B/K)=2; When K=2, A*B/gcd(A/K,B/K)=4; 2+4=6; )

There are N*(N+1)/2 levels in this game, and every level is an unique rectangle. (1x1 , 2x1, 2x2, 3x1, ..., Nx(N-1), NxN)

FSF has played this game for a long time, and he finally gets all the coins in the game.
Unfortunately ,he uses an UNSIGNED 32-BIT INTEGER variable to count the number of coins.
This variable may overflow.
We want to know what the variable will be.
(In other words, the number of coins mod 2^32)
 

Input
There are multiply test cases.

The first line contains an integer T(T<=500000), the number of test cases

Each of the next T lines contain an integer N(N<=500000).
 

Output
Output a single line for each test case.

For each test case, you should output "Case #C: ". first, where C indicates the case number and counts from 1.

Then output the answer, the value of that UNSIGNED 32-BIT INTEGER variable.
 

Sample Input
313100
 

Sample Output
Case #1: 1Case #2: 30Case #3: 15662489
Hint
In the second test case, there are six levels(1x1,1x2,1x3,2x2,2x3,3x3)Here is the details for this game:1x1: 1(K=1); 1x2: 2(K=1); 1x3: 3(K=1); 2x2: 2(K=1), 4(K=2); 2x3: 6(K=1); 3x3: 3(K=1), 9(K=3); 1+2+3+2+4+6+3+9=30
 题目意思很清楚 求1*n-n*n中 i*j/ gcd(i/K,j/K)的和,K为i,j的公因子。。
昨天比赛的时候求前缀和的思路已经有了,但是对原来那个公式的化简出现了问题,化了一个丑陋的姿势导致到后面根本没办法动手。
很显然i*j/gcd(i/k,j/k)<=>i*j/gcd(i,j)/k昨天看到这个蛮开心直接写成了lcm(i,j)*k然后就GG了,根本没办法搞下去。。。
今天看了下冷月之殇大神的BLOG,i*j/gcd(i/k,j/k)<=>i*j/k直接吓尿,后面自己想了想加举了例子发现的确没错 因为K是i,j的公因子,所以gcd(i,j)/K最后的值还在K中。
如i=6,j=12  k=1 2 3 6 然后gcd(i,j)/k=6,2,3,1所以将原公式等价一下即为:i*j/gcd(i/k,j/k)<=>i*j/gcd(i,j)/k<=>i*j/k记为fun(i,j);
再利用前缀和的思想可以知道sum[n]=sum[n-1]+∑fun(i,n)[1<=i<=n],接下来就是处理fun(i,n)的过程了,当然sum[1]=1;
再来看∑fun(i,n)[1<=i<=n],我们进一步求出i,n的最大公约数的所有公因子记为p1,p2,.....pn,那么∑fun(i,n)[1<=i<=n]=n*∑(pi/pi+2pi/pi+....numi*pi/pi)[1<=i<=n]<=>n*∑(1+numi)*numi/2, numi代表当前1-n最多能是pi的多少倍,也就是若i与n含有公因子pi,那么结果sum+=n*i/pi。那么对于1<=i<=n,中含有pi这个因子的有pi,2*pi,numi*pi。那么sum+=n*(1+2+...+numi)=(n/pi+1)*(n/pi)/2*n,再记∑(1+numi)*numi/2为ans[i]预处理好ans数组,再进一步处理前缀和数组,打好表就可以了。。
代码很短了,在此膜拜下冷月之殇大牛,思路基本有了,代码跟他的几乎一样。。。感觉有一种事后诸葛亮的即视感,结果我还不能算是事后的诸葛亮,事前猪一样还差不多。。。简直水成马啊T T。。。
#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>using  namespace std;const long long mod=4294967296LL;const int maxn=500005;long long ans[maxn],sum[maxn];int n;void fun(int n){    for(long long i=1;i<n;i++)//枚举因子    {        for(long long j=i;j<n;j+=i)//每个因子从i-n最多有j/i个然后记录和        {            ans[j]+=(j/i+1)*(j/i)/2;        }    }}void dabiao(){    memset(ans,0,sizeof(ans));    fun(maxn);    sum[1]=1; //cout<<sum[1]<<"~"<<endl;   for(long long i=2;i<maxn;i++)    {        sum[i]=sum[i-1]+ans[i]*i;        sum[i]=sum[i]%mod;    }}int main(){    dabiao();   int t;    int cas=0;    scanf("%d",&t);    while(t--)    {        scanf("%d",&n);        printf("Case #%d: %I64d\n",++cas,sum[n]);    }    return 0;}



0 0
原创粉丝点击