20181104
orzxiaoyaoorzxiaoyaoorzxiaoyaoorzxiaoyaoorzxiaoyaoorzxiaoyaoorzxiaoyao
T1 3986: 物理课(physics)
题目描述
wzy正在上物理课!他发现了一个完全不会的题目:caoxia在一个奇妙的星球上(重力加速度为g)踢了一只猫,猫飞起的路线与地面夹角为θ (角度制),初速度为v,猫非常地开心,所以每次落地后会自己反弹,但反弹后速度会乘以一个常数d(0≤d<1)。请问猫最后的落点离起点多远?(猫飞行时方向不会改变,飞行过程中不计空气阻力与摩擦力,所有数值单位均为国际标准单位制)
0≤v≤1000,0<g≤1000,0≤d<1,0<θ<90,T≤50,000.
题解
显然用信竞的方法,我们可以每次把v乘上d算出答案,直到v<1e-5(1e-4会错的QAQ,被卡了12分嘤嘤嘤)
(正解)用数学方法就是等比数列求和
啥也别说了上代码吧
#include <cstdio>
#include <cmath>
#define db double
using namespace std;
int T;db a,v,d,g,s;
int main(){
for (scanf("%d",&T);T--;){
scanf("%lf%lf%lf%lf",&a,&v,&d,&g);s=0;
while(v>=1e-5)
s+=2.0*v*sin(M_PI*a/180)/g*v*cos(M_PI*a/180),
v*=d;
printf("%.5lf\n",s);
}
return 0;
}
T2 3987: 数学课(math)
题目描述
wzy又来上数学课了…… 虽然他很菜,但是数学还是懂一丢丢的。老师出了一道题,给定一个包含n个元素的集合P=1,2,3,…,n,求有多少个集合A⊆P,满足任意x∈A有2x∉A,且对于A在P中的补集B,也满足任意x∈B有2x∉B。
wzy花费了1E100天终于算出来了这个答案,但是可恶的caoxia居然又加了一个条件!他要求A的大小恰好为m,这样又有多少个A呢?
这回wzy真的不会了,他找到了你,希望能够得到帮助。由于答案太大,你只需要输出答案mod10000019即可。
n,m≤1e18,q≤100000
题解
(考场终于找到规律了然后效率O(n)依旧过不去)
可以想到每个奇数和他乘上2的若干次方应该是奇偶分成两半的
设其有x个
如果个数为奇数,可以分成x/2和x/2+1
为偶数则刚好分成x/2两半
假设奇数个数的数目为A,偶数个数为B,至少要选v个
则我们可以选出m-v个奇数的,偶数的可以随便选
答案:
具体见代码(lucas写错了QAQ)
#include <bits/stdc++.h>
#define LL long long
#define I inline
#define E register
using namespace std;
const LL P=10000019;
LL n,q,jc[P],p,ny[P],t,f;
I LL K(E LL x,E LL y){
E LL A=1;while(y){
if (y&1) A=A*x%P;
x=x*x%P;y>>=1;
}
return A;
}
I LL C(E LL x,E LL y){
if (x<y) return 0;
return jc[x]*ny[y]%P*ny[x-y]%P;
}
I LL lucas(E LL x,E LL y){
if (y<=0 || x<y) return 1;
return C(x%P,y%P)*lucas(x/P,y/P)%P;
}
I LL G(E LL l,E LL r){
return (r-l+1>>1)+((l&1)&(r&1));
}
int main(){
jc[0]=1;for (E LL i=1;i<P;i++) jc[i]=i*jc[i-1]%P;
ny[P-1]=K(jc[P-1],P-2);for (E LL i=P-1;i;i--)
ny[i-1]=i*ny[i]%P;scanf("%lld%lld",&n,&q);
t=G(1,n);
for (E LL x,i=1,c;n;i++){
x=n>>1;c=G(x+1,n);
if (i&1) p+=c;
f+=c*(i>>1);n=x;
}
t=K(2,t-p);
for (E LL m;q--;){
scanf("%lld",&m);
if (m<f || m>p+f) puts("0");
else printf("%lld\n",lucas(p,m-f)*t%P);
}
return 0;
}
T3 3988: 地理课(geography)
题目描述
地理课上,老师给出了一个巨大的地图,由于世界日新月异,会有一些道路在某一时刻被删除,也会有一些道路在某一时刻被修建。这里的道路均为双向的。
老师认为,有一些城市被分在了一个连通块中可以相互到达,而有一些城市不能够相互到达。而他想知道,每个时刻所有连通块大小的乘积是多少?
wzy看到这个地图的时候就蒙了,还好那只上天的喵及时帮助了他。现在他把这个毒瘤的地图拿过来给你,想试试看你能不能求出来。由于答案可能很大,输出乘积mod1e9+7即可。
题解
考虑离线
每条边会在几段时间内出现,所以我们可以以时间为下标建一棵线段树
把每条边按照时间插入到线段树中,求答案利用分治,在递归的过程中把边并查集起来,然后在递归回去时再把fa和sz修改就ok(利用启发式合并的思想,效率最低为)
效率,具体见代码
#include <bits/stdc++.h>
#define Ls k<<1
#define Rs Ls|1
#define I inline
#define E register
using namespace std;
const int P=1e9+7,N=1e5+5;
int t,n,m,qwq[N],fa[N],sz[N];
vector<int>a[N*4];map<int,int>d[N];
struct O{int x,y;}p[N];
struct U{int x,f,se;};vector<U>g[N*4];
I int K(E int x,E int y){
E int A=1;while(y){
if (y&1) A=1ll*A*x%P;
x=1ll*x*x%P;y>>=1;
}
return A;
}
I void update(E int k,E int l,E int r,E int L,E int R,E int v){
if (L<=l && r<=R){a[k].push_back(v);return;}
E int mid=l+r>>1;if (mid>=L) update(Ls,l,mid,L,R,v);
if (mid<R) update(Rs,mid+1,r,L,R,v);
}
I int get(E int x){return fa[x]==x?x:get(fa[x]);}
I void query(E int k,E int l,E int r,E int s){
for (E int i=0;i<a[k].size();i++){
E int k1=get(p[a[k][i]].x),k2=get(p[a[k][i]].y);
if (k1==k2) continue;
if (sz[k1]<sz[k2]) swap(k1,k2);
g[k].push_back((U){k2,k1,sz[k1]});
s=1ll*s*K(sz[k1],P-2)%P*K(sz[k2],P-2)%P*(sz[k1]+sz[k2])%P;
sz[k1]+=sz[k2];fa[k2]=k1;
}
if (l==r) printf("%d\n",s);
else{
E int mid=l+r>>1;
query(Ls,l,mid,s);
query(Rs,mid+1,r,s);
}
for (E int i=g[k].size()-1;i>=0;i--){
sz[g[k][i].f]=g[k][i].se;
fa[g[k][i].x]=g[k][i].x;
}
return;
}
int main(){
scanf("%d%d",&n,&m);
for (E int op,x,y,i=1;i<=m;i++){
scanf("%d%d%d",&op,&x,&y);
if (x>y) swap(x,y);int id=d[x][y];
if (!id) d[x][y]=++t,qwq[t]=i,p[t]=(O){x,y};
else{
if (qwq[id]) update(1,1,m,qwq[id],i-1,id),qwq[id]=0;
else qwq[id]=i;
}
}
for (E int i=1;i<=t;i++) if (qwq[i]) update(1,1,m,qwq[i],m,i);
for (E int i=1;i<=n;i++) fa[i]=i,sz[i]=1;
query(1,1,m,1);return 0;
}