首页 > 代码库 > 2016.10.30 NOIP模拟赛 day2 AM 整理

2016.10.30 NOIP模拟赛 day2 AM 整理

题目+数据:链接:http://pan.baidu.com/s/1gfBg4h1 密码:ho7o

总共得了:130分,

1:100分  2:30分(只会这30分的暴力) 3:0(毫无思路)

虽然不高,但是比较满意,因为把自己会的分数都拿到了。

T1:100分

  1 /*
  2 T1明显是个数论题。
  3 正确的思路:把n!质因数分解,把所有质因数的指数都取到最大的偶数,它们的乘积便是最终的结果。
  4 有一种很快的方法在Eular筛中可以n!的质因数分解。
  5 if(!is_prim[i])
  6 {
  7     prim[++prim[0]]=i;
  8     ll x=n;
  9     while(x)
 10     {
 11         cs[prim[0]]+=x/prim[prim[0]];
 12         x/=prim[prim[0]];
 13     }
 14 }
 15 具体的可以用“抽数法(反正我这么叫它)”来证明。
 16 
 17 */
 18 #define N 5000010
 19 #include<iostream>
 20 using namespace std;
 21 #include<cstdio>
 22 #define Mod 100000007
 23 typedef long long ll;
 24 ll prim[N]={0};
 25 int cs[N]={0};
 26 bool is_prim[N];
 27 int n;
 28 void eular()
 29 {
 30     for(ll i=2;i<=n;++i)
 31     {
 32         if(!is_prim[i])
 33         {
 34             prim[++prim[0]]=i;
 35             ll x=n;
 36             while(x)
 37             {
 38                 cs[prim[0]]+=x/prim[prim[0]];
 39                 x/=prim[prim[0]];
 40         }
 41     }
 42     for(int j=1;j<=prim[0];++j)
 43     {
 44             if(i*prim[j]>n) break;
 45             is_prim[i*prim[j]]=true;
 46             if(i%prim[j]==0) break;
 47     }
 48     }
 49 /*    for(int i=1;i<=prim[0];++i)
 50       printf("%d\n",prim[i]);*/
 51 }
 52 void fj()
 53 {
 54     for(ll i=2;i<=n;++i)
 55     {
 56         ll x=i;
 57         while(x!=1)
 58         {
 59             for(int j=1;j<=prim[0];++j)
 60             {
 61                 if(x%prim[j]==0)
 62                 {
 63                     cs[j]++;
 64                     x/=prim[j];
 65                     break;
 66                 }
 67             }
 68         }
 69     }
 70 }
 71 ll quick_mod(ll a,ll b)//a^b
 72 {
 73     ll ret=1;
 74     while(b)
 75     {
 76         if(b&1)
 77         {
 78             ret=(ret*a)%Mod;
 79         }
 80         b>>=1;
 81         a=(a*a)%Mod;
 82     }
 83     return ret;
 84 }
 85 int main()
 86 {
 87     freopen("hao.in","r",stdin);
 88     freopen("hao.out","w",stdout);
 89     scanf("%d",&n);
 90     eular();
 91 //  fj();这是没用这个优化的部分,只能得50分。
 92     ll ans=1;
 93     for(int i=1;i<=prim[0];++i)
 94     {
 95         if(cs[i]%2==0)
 96         {
 97             ans=(ans*quick_mod(prim[i],cs[i]))%Mod;
 98         }
 99         else{
100             ans=(ans*quick_mod(prim[i],cs[i]-1))%Mod;
101         }
102     }
103     cout<<ans%Mod<<endl;
104     fclose(stdin);
105     fclose(stdout);
106     return 0;
107 }

T2:

/*这道题目内部的转化非常巧妙,
首先[l,r]->[0,r]-[0,l-1]
现在只讨论r
Σxi/m -r<=0 --> ∑(xi-r)/m<=0 ==>∑(xi-m)<=0:
题目==>询问有多少区间和小于等于0
做一个前缀和S,现有[a,b] 要满足 s[b]-s[a]<=0 :
询问有多少对a,b使s[b]<=s[a] --> 求逆序对
注意这道题目的转换,十分的巧妙。
--------*****------
另外求逆序对有两种方法:归并排序或者树状数组,第二种请自行百度。
*/

2016.10.30 NOIP模拟赛 day2 AM 整理