林sir (mathbb{AK})
气抖冷,林sir居然站起来了
我 = = 算了
不开 long long
见祖宗
T1: 30 ( ightarrow) 0
T1:简单的区间
简单分治 并不
一定要养成 #define int long long
的好习惯啊 (滑稽)
在分治时,先处理完本层跨过终点的合法区间,然后向下递归。在本层处理时,分最大值在中点左边和最大值在中点右边处理。下面以在中点左边为例:
设左右端点的指针是 (i,j),中点左边的和为 (sumi),中点右边的和为 (sumj)。合法区间需要满足 (sumi+sumj-Maxequiv 0pmod k)。那么 (i) 一步步向左扩展,我们需要找到一个符合条件的 (sumj),我们只需要开桶维护即可,符合条件的 (sumj) 即是 (k-sumi+Max)。
然后就是中点右面,反过来即可。
注意清空桶的时候不要 memset
,否则会和暴力一个分。
HISKrrr:这真是板子题
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+10;
int n,K,ans;
int a[maxn];
inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
}
int top;
int cnt[maxn],sta[maxn];
void Solve(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
int i=mid,j=mid+1;
int Max=0,sumi=0,sumj=0;
for(i=mid;i>=l;i--){
Max=max(Max,a[i]);sumi=(sumi+a[i])%K;
while(a[j]<=Max&&j<=r){
sumj=(sumj+a[j])%K;
cnt[sumj]++;sta[++top]=sumj;
j++;
}
ans+=cnt[((K-sumi+Max)%K+K)%K];
}
while(top)cnt[sta[top--]]=0;
i=mid,j=mid+1;
Max=0,sumi=0,sumj=0;
for(j=mid+1;j<=r;j++){
Max=max(Max,a[j]);sumj=(sumj+a[j])%K;
while(a[i]<Max&&i>=l){//注意这不能取等了,否则会重
sumi=(sumi+a[i])%K;
cnt[sumi]++;sta[++top]=sumi;
i--;
}
ans+=cnt[((K-sumj+Max)%K+K)%K];
}
while(top)cnt[sta[top--]]=0;
Solve(l,mid);
Solve(mid+1,r);
}
signed main(){
#ifndef LOCAL
freopen("interval.in","r",stdin);
freopen("interval.out","w",stdout);
#endif
n=read();K=read();
for(int i=1;i<=n;i++)
a[i]=read();
Solve(1,n);
printf("%lld
",ans);
return 0;
}
T2:简单的玄学
很玄学。(1leq nleq 10^{18},2leq mleq 10^{18})。
显然答案是 (1-cfrac{(2^n)^{underline m}}{2^{nm}}=1-cfrac{prodlimits_{i=2^n-m+1}^{2^n-1}i}{2^{n(m-1)}})。忽略前面的 (1) 算后面即可。但是存不下。注意到模数很小,所以可以在这上面下手。
所以我们发现当 (m>10^6+3) 的时候,取模一定是 (0) 了,直接 break
掉就行了。
所以还有约分这个事。发现能约的因子只有 (2)。
对于任意一个 (1leq a<2^n),(a) 与 (2^n-a) 的中 2 的次数相同。
所以我们要求的就是 ((m-1)!) 中因子 (2) 的个数。这个有一个 (O(log m)) 的经典做法。
for(int i=2;i<=m;i<<=1)
cnt+=m/i;
例如 (m-1=9),那以上代码就是模拟的以下过程:
1 × 2 × 3 × 4 × 5 × 6 × 7 × 8 × 9
1 1 1 1 i=2
1 1 i=4
1 i=8
发现每个数都正好被统计了 (2) 的因数个数次。
其实没必要真的去约分。我们求出来个数之后,(a) 和 (b) 都乘上 (2) 的逆元的个数次方即可。
还有要注意的就是算分母的时候不要 qpow(2,n*m)
了,否则直接爆掉 long long
。
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int Mod=1e6+3;
const int inv2=500002;
int n,m;
inline int qpow(int x,int b){
int ans=1,base=x;
while(b){
if(b&1)ans=ans*base%Mod;
base=base*base%Mod;
b>>=1;
}
return ans;
}
signed main(){
#ifndef LOCAL
freopen("random.in","r",stdin);
freopen("random.out","w",stdout);
#endif
scanf("%lld%lld",&n,&m);
if((double)log2(m)-(double)n>1e-6)return !puts("1 1");
int a=1,p=qpow(2,n),b=qpow(p,m);
for(int i=1;i<=m;i++){
a=a*(p-i+1)%Mod;
if(!a)break;
}
int cnt=n;m--;
for(int i=2;i<=m;i<<=1)
cnt+=m/i;
a=a*qpow(inv2,cnt)%Mod;
b=b*qpow(inv2,cnt)%Mod;
printf("%lld %lld
",(b-a+Mod)%Mod,b);
return 0;
}
T3:简单的填数
瞎贪得 10 分
正解是贪心加模拟,比较麻烦,以后有时间补吧
T4:聪聪和可可
原题,但没做过。
用 bfs 预处理两点之间最短路距离和猫走的路径,然后可以用记忆化搜索简单转移。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int n,m,ccst,kkst;
int deg[maxn];
double ans;
struct Edge{
int from,to,nxt;
}e[maxn<<1];
inline int read(){
int x=0;bool fopt=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')fopt=0;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-48;
return fopt?x:-x;
}
int head[maxn],cnt;
inline void add(int u,int v){
e[++cnt].from=u;
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
int dis[maxn][maxn],p[maxn][maxn];//猫在i,鼠在j,猫下一步走p[i][j]
void bfs(int s){
queue<int> q;
q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
int temp=p[s][u];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[s][v]==-1||(dis[s][u]+1==dis[s][v]&&temp<p[s][v])){
dis[s][v]=dis[s][u]+1;
p[s][v]=temp?temp:v;//p[s][s]==0 那v就是下一步
q.push(v);
}
}
}
}
double f[maxn][maxn];
double dfs(int cpos,int kpos){
if(cpos==kpos)return 0;
if(p[cpos][kpos]==kpos||p[p[cpos][kpos]][kpos]==kpos)return f[cpos][kpos]=1.0;
if(f[cpos][kpos])return f[cpos][kpos];
double sum=dfs(p[p[cpos][kpos]][kpos],kpos);
for(int i=head[kpos];i;i=e[i].nxt){
int v=e[i].to;
sum+=dfs(p[p[cpos][kpos]][kpos],v);
}
return f[cpos][kpos]=1.0*sum/(deg[kpos]+1)+1;
}
int main(){
#ifndef LOCAL
freopen("cchkk.in","r",stdin);
freopen("cchkk.out","w",stdout);
#endif
memset(dis,-1,sizeof(dis));
n=read();m=read();ccst=read();kkst=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
add(u,v);add(v,u);
deg[u]++;deg[v]++;
}
for(int i=1;i<=n;i++)
bfs(i);
printf("%.3lf
",dfs(ccst,kkst));
return 0;
}