幸运数字(number)
Time Limit:1000ms Memory Limit:64MB
题目描述
LYK 最近运气很差,例如在 NOIP 初赛中仅仅考了 90 分,刚刚卡进复赛,于是它决定使
用一些方法来增加自己的运气值。
它觉得,通过收集幸运数字可以快速的增加它的 RP 值。
它给幸运数字下了一个定义: 如果一个数 x 能被 3 整除或被 5 整除或被 7 整除, 则这个
数为幸运数字。
于是它想让你帮帮它在 L~R 中存在多少幸运数字。
输入格式(number.in)
第一行两个数 L,R。
输出格式(number.out)
一个数表示答案。
输入样例
10 15
输出样例
4
数据范围
对于 50%的数据 $1leq Lleq Rleq 10^5$。
对于 60%的数据 $1leq Lleq Rleq 10^9$。
对于 80%的数据 $1leq Lleq Rleq 10^{18}$。
对于 90%的数据 $1leq Lleq Rleq 10^{100}$。
对于另外 10%的数据 $L=1,1leq Rleq 10^{100}$。
对于 100%的数据 L,R 没有前导 0。
思路分析:
数论太弱了,容斥原理都不会。。。
简单说一下容斥原理,用的最多的是三集合容斥原理。公式:
$left|Acup Bcup C ight| = left|A ight| + left|B ight| + left|C ight| - left|Acap B ight| - left|Bcap C ight| - left|Ccap A ight| + left|Acap Bcap C ight|$
然后就是一顿套公式啊。
看到前导0,$10^{100}$高精的节奏啊。一顿套高精...
OMG,还是80分弃疗吧,毕竟太弱了。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <iostream> 5 #include <algorithm> 6 #include <string> 7 #include <cstring> 8 using namespace std; 9 //int L,R; 10 //int work(int x,int y) {return x/y;} 11 char s1[1005],s2[1005]; 12 int S1[1005],S2[1005],len1,len2,s[1005],S[1005],i; 13 void pl(int *a,int *b) 14 { 15 for (int i=a[0]+1; i<=b[0]; i++) a[i]=0; 16 for (int i=1; i<=b[0]; i++) a[i]+=b[i]; 17 a[0]=max(a[0],b[0]); 18 for (int i=1; i<a[0]; i++) if (a[i]>=10) {a[i+1]++; a[i]-=10;} 19 if (a[a[0]]>=10) {a[a[0]+1]=1; a[a[0]]-=10; a[0]++;} 20 } 21 void mn(int *a,int *b) 22 { 23 for (int i=a[0]+1; i<=b[0]; i++) a[i]=0; 24 for (int i=1; i<=b[0]; i++) a[i]-=b[i]; 25 for (int i=1; i<a[0]; i++) 26 if (a[i]<0) {a[i]+=10; a[i+1]--;} 27 while (a[0]>1 && a[a[0]]==0) a[0]--; 28 } 29 void work(int *a,int b,int *c) 30 { 31 for (int i=1; i<=a[0]; i++) c[i]=a[i]; 32 for (int i=a[0]; i>=1; i--) 33 { 34 c[i-1]+=c[i]%b*10; 35 c[i]/=b; 36 } 37 c[0]=a[0]; 38 while (c[0]>1 && c[c[0]]==0) c[0]--; 39 } 40 int main() 41 { 42 cin>>L>>R; 43 cout<<work(R,3)+work(R,5)+work(R,7)-work(R,15)-work(R,21)-work(R,35)+work(R,105)- 44 work(L-1,3)-work(L-1,5)-work(L-1,7)+work(L-1,15)+work(L-1,21)+work(L-1,35)-work(L-1,105); 45 return 0; 46 freopen("number.in","r",stdin); 47 freopen("number.out","w",stdout); 48 scanf("%s",s1); 49 scanf("%s",s2); 50 len1=strlen(s1); 51 len2=strlen(s2); 52 for (i=1; i<=len1; i++) S1[len1-i+1]=s1[i-1]-'0'; 53 S1[0]=len1; 54 for (i=1; i<=len2; i++) S2[len2-i+1]=s2[i-1]-'0'; 55 S2[0]=len2; 56 work(S2,3,s); 57 work(S2,5,S); 58 pl(s,S); 59 work(S2,7,S); 60 pl(s,S); 61 work(S2,15,S); 62 mn(s,S); 63 work(S2,21,S); 64 mn(s,S); 65 work(S2,35,S); 66 mn(s,S); 67 work(S2,105,S); 68 pl(s,S); 69 S[0]=1; S[1]=1; 70 mn(S1,S); 71 work(S1,15,S); 72 pl(s,S); 73 work(S1,21,S); 74 pl(s,S); 75 work(S1,35,S); 76 pl(s,S); 77 work(S1,3,S); 78 mn(s,S); 79 work(S1,5,S); 80 mn(s,S); 81 work(S1,7,S); 82 mn(s,S); 83 work(S1,105,S); 84 mn(s,S); 85 for (i=s[0]; i>=1; i--) cout<<s[i]; 86 return 0; 87 }
蚂蚁运输(ant)
Time Limit:5000ms Memory Limit:64MB
题目描述
LYK 在观察一些蚂蚁。
蚂蚁想要积攒一些货物来过冬。积攒货物的方法是这样的。
对于第i只蚂蚁, 它要从li出发, 拿起货物, 走到ri处放下货物, 需要消耗的时间为|ri-li|。
而且所有蚂蚁都是可以同时进行的,也就是说,假如有 m 只蚂蚁,那么运输完货物的时间
为 max{|ri-li|}。
LYK 决定帮蚂蚁一把,它发明了空间传输装置。具体地,当蚂蚁走到 X 处时,它可以不
耗费任意时间的情况下瞬间到达 Y,或者从 Y 到达 X。也就是说,一个蚂蚁如果使用了空间
传输装置,它耗费的时间将会是 min{|li-X|+|ri-Y|,|li-Y|+|ri-X|},当然蚂蚁也可以选择徒步走
到目标点。
由于空间传输装置非常昂贵,LYK 打算只建造这么一台机器。并且 LYK 想让蚂蚁运输完
货物的时间尽可能短,你能帮帮它吗?
输入格式(ant.in)
第一行两个数 n,m,n 表示 li,ri 的最大值。
接下来 m 行,每行两个数 li,ri。
输出格式(ant.out)
一个数表示答案
输入样例
5 2
1 3
2 4
输出样例
1
数据范围
对于 20%的数据 n,m<=100。
对于 40%的数据 n,m<=1000。
对于 60%的数据 n<=100000,m<=1000。
对于 80%的数据 n,m<=100000。
对于 100%的数据 n,m<=1000000,1<=li,ri<=n(li=ri 时你甚至可以无视这只蚂蚁) 。
样例解释
令空间传输装置的参数中 X=2,Y=3 或者 X=3,Y=2 都行。
思路分析:
今天唯一一道比较可做的题目。
大概是二分答案。
xxy讲了大概1h左右的二分答案,感觉听懂了些。
定义答案区间为[0,1000000].
路径是无向的.....将所有路线转化为一个方向.
然后开始二分答案,推出式子来一顿套模板...
//以下为题解:
观察到答案具有可二分性。我们可以二分答案。
由于路径都是无向的,因此对于任意一条方案li,ri若li>ri则可以交换li和ri。
我们设二分的答案为x。
对于那些li+x>=ri的方案我们直接默认为可行。
我们规定X<=Y。
对于li+x<ri的方案。只有一种可能能够完成,即,从li出发,到达X,到达Y,到达ri。
也就是说,如果X确定,Y存在于一段区间内。
我们来看li>=X的情况。
先求出X=n时符合条件的Y的区间。当X慢慢减少时,这个区间肯定也在慢慢合拢,并且满足li>=X的条件也会越来越多。我们可以线性求出所有这个区间。
对于li<X的情况也同理。
这样就能做到线性判断,总复杂度nlgn。(这里默认n与m同阶)
数学神坑题啊...表示呵呵.
End.