幸运数字(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%的数据 1<=L<=R<=10^5。
对于 60%的数据 1<=L<=R<=10^9。
对于 80%的数据 1<=L<=R<=10^18。
对于 90%的数据 1<=L<=R<=10^100。
对于另外 10%的数据 L=1, 1<=R<=10^100。
对于 100%的数据 L, R 没有前导 0。
L--------
#include<cstdio> #include<cstring> #include<iostream> #define maxn 510 using namespace std; int n,cnt,a[maxn],b[maxn],c[maxn],d[maxn],A[maxn],B[maxn],C[maxn]; char L[maxn],R[maxn]; void Div(){ int x=0; for(int i=a[0];i>=1;i--){ x=x*10+a[i]; b[i]=x/105; x-=b[i]*105; } for(int i=a[0];i>=1;i--) if(b[i]){ b[0]=i;break; } } void Mul1(){ c[0]=b[0]; for(int i=1;i<=c[0];i++) c[i]=b[i]*105; for(int i=1;i<=c[0];i++) if(c[i]>9){ c[i+1]+=c[i]/10; c[i]%=10; } while(c[c[0]+1]){ c[0]++;c[c[0]+1]+=c[c[0]]/10;c[c[0]]%=10; } } void Mul2(){ for(int i=1;i<=b[0];i++) b[i]=b[i]*57; for(int i=1;i<=b[0];i++) if(b[i]>9){ b[i+1]+=b[i]/10; b[i]%=10; } while(b[b[0]+1]){ b[0]++;b[b[0]+1]+=b[b[0]]/10;b[b[0]]%=10; } } void Jian(){ for(int i=1;i<=a[0];i++) d[i]=a[i]-c[i]; for(int i=1;i<=a[0];i++) if(d[i]<0){ d[i]+=10;d[i+1]--; } for(int i=a[0];i>=1;i--) if(d[i]){ d[0]=i;break; } } void Jian2(){ for(int i=1;i<=B[0];i++) C[i]=B[i]-A[i]; for(int i=1;i<=B[0];i++) if(C[i]<0){ C[i]+=10;C[i+1]--; } for(int i=B[0];i>=1;i--) if(C[i]){ C[0]=i;break; } } void Add(int x){ b[1]+=x;int p=1; while(b[p]>9){ b[p+1]+=b[p]/10;b[p]%=10;p++;b[0]=max(b[0],p); } if(b[b[0]+1])b[0]++; } int Get(){ int r=0; for(int i=d[0];i>=1;i--) r=r*10+d[i]; return r; } void Cl(){ memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); memset(d,0,sizeof(d)); } int main() { freopen("number.in","r",stdin); freopen("number.out","w",stdout); scanf("%s%s",L,R); a[0]=strlen(L); for(int i=1;i<=a[0];i++) a[i]=L[a[0]-i]-‘0‘; a[1]--; int p=1; while(a[p]<0){ a[p]+=10;a[p+1]--; } if(a[a[0]]==0)a[0]--; Div();Mul1();Jian();Mul2(); n=Get();cnt=0; for(int i=1;i<=n;i++) if(i%3==0||i%5==0||i%7==0)cnt++; Add(cnt); for(int i=0;i<=b[0];i++)A[i]=b[i]; Cl(); a[0]=strlen(R); for(int i=1;i<=a[0];i++) a[i]=R[a[0]-i]-‘0‘; Div();Mul1();Jian();Mul2(); n=Get();cnt=0; for(int i=1;i<=n;i++) if(i%3==0||i%5==0||i%7==0)cnt++; Add(cnt); for(int i=0;i<=b[0];i++)B[i]=b[i]; Jian2(); for(int i=A[0];i>=1;i--) printf("%d",A[i]);printf("\n"); for(int i=B[0];i>=1;i--) printf("%d",B[i]);printf("\n"); for(int i=max(C[0],1);i>=1;i--) printf("%d",C[i]);printf("\n"); return 0; }
位运算(bit)
Time Limit:2000ms Memory Limit:64MB
题目描述
lyk 最近在研究位运算。它发现除了 xor,or,and 外还有很多运算。
它新定义了一种运算符“#” 。
具体地,可以由 4 个参数来表示。 令 a[i][j]表示 i#j。 其中 i,j 与 a 的值均∈[0,1]。
当然问题可以扩展为>1 的情况,具体地,可以将两个数分解为 p 位,然后对于每一位
执行上述的位运算,再将这个二进制串转化为十进制就可以了。
例如当 a[0][0]=0, a[1][1]=0, a[0][1]=1, a[1][0]=1 时,3#4 在 p=3 时等于 7,2#3 在
p=4 时等于 1(实际上就是异或运算)。
现在 lyk 想知道的是,已知一个长为 n 的数列 b。它任意选取一个序列 c,满
足 c1<c2<...<ck,其中 1≤c1 且 ck≤n,定义这个序列的价值为 b{c1}#b{c2}#...#b{ck}
的平方。
这里我们假设 k 是正整数,因此满足条件的 c 的序列个数一定是 2^n−1 。 lyk 想知道
所有满足条件的序列的价值总和是多少。
由于答案可能很大, 你只需输出答案对 1,000,000,007 取模后的结果即可。
输入格式(bit.in)
第一行两个数 n,p。
第二行 4 个数表示 a[0][0], a[0][1], a[1][0], a[1][1]。
第三行 n 个数表示 bi(0<=bi<2^p)。
输出格式(bit.out)
一个数表示答案。
输入样例
3 30
0 1 1 0
1 2 3
输出样例
28
样例解释
{1}的价值为 1, {2}的价值为 4, {3}的价值为 9, {1,2}的价值为 9, {1,3}的价值为 4, {2,3}
的价值为 1, {1,2,3}的价值为 0,因此 7 个子集的价值总和为 28。
数据范围
总共 10 组数据。
对于第 1,2 组数据 n<=5。
对于第 3,4 组数据 n<=10000, p=1。
对于第 5 组数据 a 值均为 0。
对于第 6 组数据 a 值均为 1。
对于第 7 组数据 a[0][0]=0,a[1][0]=0,a[1][1]=1,a[0][1]=1。
对于第 8,9 组数据 n<=1000, p<=10。
对于所有数据 n<=10000, 1<=p<=30。
考试的时候读错题爆零了233
正解你猜
蚂蚁运输(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 都行。
二分+模型转化+数学公式
/* 听了琴神的方法 %%% 很好地模型转化 有大部分的点 l>r 先预处理一下 对于 r-l<=x 的直接忽略 另外的 走X Y 假设 X < Y 那么一定是 Abs(L-X)+Abs(R-Y) 不妨把 XY LR 看做二维平面内的两个点 这个就是表示的他的曼哈顿距离 那么问题就转化成了 对于二分到的答案Mid 能不能找到一对 X Y 使得 以(X,Y)为中心的 倾斜45°正方形能覆盖所有的第二类点 这里直接无脑求得点到直线的距离(不会旋转坐标系) 然后 然后就没了 */ #include<iostream> #include<cstdio> #include<cmath> #define inf 1e8 #define G 1.4142135623730950488016887242097 #define ld long double #define maxn 1000010 using namespace std; int n,m,L[maxn],R[maxn],ans,X,Y; ld xi[maxn],yi[maxn]; int init(){ int x=0,f=1;char s=getchar(); while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();} while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} return x*f; } ld Abs(ld x){ return x>0?x:-x; } ld Min(ld x,ld y){ return x<y?x:y; } ld Max(ld x,ld y){ return x>y?x:y; } ld Cal(ld A,ld B,ld C,ld x,ld y){ ld X=Abs((A*x+B*y+C)/(sqrt(A*A+B*B))); if(y>x&&B==-1)X=-X; return X; } bool Judge(int x){ ld x1=inf,y1=inf,x2=-inf,y2=-inf; for(int i=1;i<=m;i++){ if(R[i]-L[i]<=x)continue; x1=Min(x1,xi[i]);y1=Min(y1,yi[i]); x2=Max(x2,xi[i]);y2=Max(y2,yi[i]); } int now=ceil(Max(x2-x1,y2-y1)/(ld)(G)); return now<=x; } int main() { freopen("ant.in","r",stdin); freopen("ant.out","w",stdout); n=init();m=init(); for(int i=1;i<=m;i++){ L[i]=init();R[i]=init(); if(L[i]>R[i])swap(L[i],R[i]); xi[i]=Cal(1,-1,0,(ld)L[i],(ld)R[i]); yi[i]=Cal(1,1,0,(ld)L[i],(ld)R[i]); } int l=0,r=n; while(l<=r){ int mid=l+r>>1; if(Judge(mid)){ ans=mid;r=mid-1; } else l=mid+1; } cout<<ans<<endl; return 0; }