等式转换降低时间复杂度

ECJTU16级校赛

 

 

第四题:

LB的公式

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 40   Accepted Submission(s) : 16
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

LB是个十分喜欢钻研的人,对什么事都要搞明白。 有一天他看到一个公式,((a-b)*c+d*e)/f=k。他想如果给定K的值, 一共有多少种不同整数的组合(a,b,c,d,e,f)使公式成立,(-50≤a,b,c,d,e,f≤50)LB算了很久都没有算出来, 所以他向你求助,由于答案很大,所以对1e9+7取模

Input

第一行只包含一个整数T(T≤100),表示测试用例的个数。 对于每个测试用例,第一行只包含一个整数K(-500≤K≤500)

Output

对于每个测试用例,输出最后对1e9+7取模的答案。

Sample Input

1
500

Sample Output

27194104

移项,得(a-b)*c=k*f-d*e,易得公式左边取值范围为[-5000,5000],暴力求解出公式左右两边值为N的不同个数x,然后分别对应相乘,再求和、取模,时间复杂度为o(n^3),n为50,注意f不能为0。
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<set>
 7 #include<map>
 8 #define ll long long
 9 using namespace std;
10 const ll eps=1e9+7;
11 const int mod=eps;
12 const int N=1e5+5;
13 // map<int,int>mp1;
14 //map<int,int>mp2;
15 int main()
16 {
17     int t,k,b,a,c,d,e,f,mp1[60001],mp2[60001];ll ans;
18     scanf("%d",&t);
19     while(t--)
20     {
21         ans=0;
22         memset(mp1,0,sizeof(mp1));
23         memset(mp2,0,sizeof(mp2));
24         scanf("%d",&k);
25         for(a=-50;a<=50;a++)
26         for(b=-50;b<=50;b++)
27         for(c=-50;c<=50;c++)
28         {
29             mp1[(a-b)*c+27500]++;
30         }
31         for(f=-50;f<=50;f++)
32         for(d=-50;d<=50;d++)
33         for(e=-50;e<=50;e++)
34         {
35             if(f!=0)mp2[(k*f-d*e)+27500]++;
36         }
37         for(int i=0;i<60000;i++)
38         {
39             ans+=mp1[i]*mp2[i];//printf("%d  %d\n",mp1[i],mp2[i]);
40         }
41         //printf("%lld\n",ans);
42         printf("%lld\n",ans%mod);
43     }
44     return 0;
45 }

第一个式子的范围为(-5000,5000),第二个式子 的范围为(-27500,27500)

所以数组下标+27500;

一开始用了map超时,因为不会将map清0,所以每次都新创建了map应该是这里的原因

 

第五题:

最近侯ry感觉自己在数学方面的造诣不忍直视;他发现他的学习速率呈一个指数函数递增,疯狂的陷入学习的泥潭,无法自拔;他的队友发现了他的学习速率y=e^(b*lna+lnc); e是科学界非常重要而常见的常数,e=2.718281828……。 侯ry由于数学很差不会算学习数率y,现求助于学弟,感激不尽;

Input

多组数据,每组数据输入三个整数a,b,c(a,c<=10^12,b<=10^100000)

Output

一个整数y,对10^9+7取模

Sample Input

2 3 10

Sample Output

80


欧拉定理:对于互质的正整数a和n,有a^phi(n)≡1 mod n,题目求a^b*c%mod;把b%(mod-1)即可快速幂一下。


 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define ll long long
 6 const ll eps=1e9+7;
 7 const int mod=eps;
 8 using namespace std;
 9 int main()
10 {
11     ll a,b,c,pinb,i,j,k,l,ans;char bstr[100005];
12     while(~scanf("%lld",&a))
13     {
14         scanf("%s%lld",bstr,&c);
15         l=strlen(bstr);k=0;ans=1;b=0;
16         for(i=0;i<l;i++)
17         {
18             b=b*10+(bstr[i]-'0');
19             if(b>=mod-1)b%=mod-1,k=1;
20         }
21         //cout<<mod-1<<endl;
22         if(k==1)b+=mod-1;
23         a%=mod;
24         while(b>0)
25         {
26             if(b&1)ans=(ans*a)%mod;
27             a=(a*a)%mod;
28             b>>=1;
29         }
30         printf("%lld\n",ans*(c%mod)%mod);
31     }
32     return 0;
33 }

质数n的欧拉数为n-1,欧拉数的定义为:小于等于n的数中有多少个和他互质的数,质数除了不与自己互质,1~n-1都互质

以下是百度的类似的模板

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define ll long long
 6 const ll eps=1e9+7;
 7 const int mod=eps;
 8 using namespace std;
 9 /*ll powmod(ll a,ll n)
10 {
11     ll ans=1;
12     a%=mod;
13     while(n>0)
14     {
15         if(n&1)ans=(ans*a)%mod;
16         n/=2;
17         a=(a*a)%mod;
18     }
19     return ans;
20 }
21 int main()
22 {
23     ll a,b,c;
24     while(~scanf("%lld%lld%lld",&a,&b,&c))
25     {
26         c%=mod;
27         //printf("%d\n",powmod(a,b));
28         ll ans=(powmod(a,b)*c)%mod;
29         printf("%lld\n",ans);
30     }
31     return 0;
32 }*/
33 const __int64 c=1e9+7;
34 char b[1000005];
35 __int64 phi(__int64 a)  //求欧拉函数值
36 {
37     __int64 ans=a;
38     for(int i=2;i*i<=a;i++)
39     {
40         if(a%i==0)
41         {
42             ans=ans/i*(i-1);
43             while(a%i==0) a/=i;
44         }
45     }
46     if(a>1) ans=ans/a*(a-1);
47     return ans;
48 }
49 int main()
50 {
51     __int64 a,t,d,phic,newb,len,i;
52     while(~scanf("%I64d",&a))
53     {
54         bool flag=false; //b是否大于phic
55         scanf("%s%I64d",b,&d);
56         a%=c,t=1,phic=phi(c),len=strlen(b),newb=0;
57         for(i=0;i<len;i++)   //求b%phi(c)
58         {
59             newb=newb*10+(b[i]-'0');
60             if(newb>=phic) newb%=phic,flag=true;
61         }
62         if(flag==true) newb+=phic;  //新的指数为b%phi(c)+phi(c)
63         while(newb-1)
64         {
65             if(newb&1) t=t*a%c;
66             newb>>=1,a=a*a%c;
67         }
68         printf("%I64d\n",(a*t%c)*(d%c)%c);
69     }
70     return 0;
71 }

第七题:

acm小学妹

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 49   Accepted Submission(s) : 19
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

ACM小学妹在今天的暑假训练结束后,想看球赛放松一下。当他打开电脑时查询到联盟今天直播N场球赛,每场球赛的起止时间(S1,E1),(S2,E2),...,(SN,EN)。现在小学妹想今天看完所有的球赛直播,不至于留到明天看重播了,毕竟明天依旧是要训练的。当小学妹看完这场球赛要切换到其他球赛时是不需要时间的。现在小学妹用自己训练用的电脑来看球赛,但是可能不够。毕竟小学妹自己的电脑最多只能同时播放1场直播,现在小学妹需要借一些电脑来同时播放球赛。本来小学妹自己是可以求出最少需要借多少台电脑来同时观看的,但是今天训练太累了,你可以帮助他吗?

Input

包含多组输入,第一行输入一个整数N(1≤N≤100000),表示任务的数目。以下N行每行两个整数Si,Ei,(0≤Si<Ei≤1000000000),表示任务的起至时间。

Output

输出小学妹最少需要借的电脑数目。

Sample Input

5
1 10
2 7
6 9
3 4
7 10

Sample Output

2


题解:

 .每场球赛的起始时间s:x=s,y=1;每场球赛的终止时间e:x=e,y=-1,按x非递减排序,x相同按y非递减排序。输出y的前缀和的最大值。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define ll long long
 6 const ll eps=1e9+7;
 7 const int mod=eps;
 8 const int N=1e5+5;
 9 struct TV
10 {
11     ll time;
12     int ps;
13     bool operator < (TV a)const{
14         if(a.time==time)
15             return a.ps>ps;
16         else
17         return a.time>time;
18     }
19 }tv[N];
20 using namespace std;
21 int main()
22 {
23     ll i,j,n;int f[2*N],ans;
24     while(~scanf("%lld",&n))
25     {
26         memset(f,0,sizeof(f));
27         for(i=0;i<2*n;i+=2)
28         {
29             scanf("%lld%lld",&tv[i].time,&tv[i+1].time);
30             tv[i].ps=1;tv[i+1].ps=-1;
31         }
32         ans=0;f[0]=tv[0].ps;
33         sort(tv,tv+2*n);
34         for(i=1;i<2*n;i++)
35         {
36             f[i]=f[i-1]+tv[i].ps;
37             ans=max(f[i],ans);
38         }
39         /*for(i=0;i<2*n;i++)
40         {
41             printf("%d ",tv[i].ps);
42         }
43         printf("\n");
44         for(i=0;i<2*n;i++)
45         {
46             printf("%lld ",tv[i].time);
47         }
48         printf("\n");
49         for(i=0;i<2*n;i++)
50         {
51             printf("%d ",f[i]);
52         }
53         printf("\n");*/
54         if(ans>0)
55         printf("%d\n",ans-1);
56         else
57         printf("0\n");
58     }
59     return 0;
60 }
61 /*
62 5
63 1 10
64 2 7
65 5 10
66 3 6
67 7 10
68 */

第八题:

毛线数列最值

Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 43   Accepted Submission(s) : 15
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

halfyarn找你写个简单的题?好哒!给你n个整数,现在要求你选择两个位置的数,例如选择第pos_a个数a,和第pos_b个数b,给定ans=min(a,b)*abs(pos_a-pos_b),输出ans的最大值。

Input

第一行输入一个n代表有n个数,接下来的一行输入n个整数; 2<=n<=1e6; 1<=a,b<=1e6; 注意多组输入;

Output

ans的最大值;

Sample Input

4
1 2 2 2

Sample Output

4


O(n)处理,注意开LL,取数列的左右界l,r,得到初始答案ans,每次取min(a[l],a[r])的一侧向中心遍历,当找到更大的数时,能更新则更新答案,当l>r结束,输出ans。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define ll long long
 6 const ll eps=1e9+7;
 7 const int mod=eps;
 8 const int N=1e6+5;
 9 ll a[N];
10 using namespace std;
11 int main()
12 {
13     ll r,l,i,j,n,ans;
14     while(~scanf("%lld",&n))
15     {
16         ans=0;
17         for(i=0;i<n;i++)
18         scanf("%lld",&a[i]);
19         r=0;l=n-1;
20         while(l>r)
21         {
22             ans=max(ans,min(a[r],a[l])*(l-r));
23             if(a[r]==min(a[r],a[l]))
24             r++;
25             else l--;
26         }
27         printf("%lld\n",ans);
28     }
29     return 0;
30 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值