8月5日刷题日记
8月5日刷题日记
又划了一天
P3935 Calculating
数论分块板子题,考虑作为因数出现的次数。
\[Ans\ \ =\ \ \sum_{i=1}^{r} \lfloor \dfrac{r}{i} \rfloor \ \ - \ \ \sum_{j=1}^{l-1}\lfloor \dfrac{l-1}{j}\rfloor
\]
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long
const int Mod=998244353;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
int L,R;
int calc(int n){
int l=1,r,res=0;
while(l<=n){
r=n/(n/l);
res=(res+((r-l+1)*(n/l)%Mod))%Mod;
l=r+1;
}
return res%Mod;
}
signed main() {
L=read(),R=read();
printf("%lld\n",((calc(R)-calc(L-1)+Mod)%Mod));
return 0;
}
[USACO06DEC]Milk Patterns G
二分爆操后缀数组,二分长度,然后移动区间搞一搞就行了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int unsigned long long
const int Mod=1e9+7;
const int base=131;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
int n,k,a[N];
int Pow(int a,int b){
int res=1;
while(b){if(b&1) res*=a;b>>=1;a*=a;}
return res;
}
bool check(int mid){
unordered_map<int,int>cnt;
int calc=0;
for(int i=1;i<=n;i++){
if(i<=mid){
calc=calc*base+a[i];
cnt[calc]++;
if(cnt[calc]>=k) return 1;
}else{
calc=calc*base+a[i];
calc-=a[i-mid]*Pow(base,mid);
cnt[calc]++;
if(cnt[calc]>=k) return 1;
}
}return 0;
}
signed main() {
n=read(),k=read();
for(int i=1;i<=n;i++)a[i]=read();
int l=1,r=n,Ans=0;
while(l<=r){
int mid=l+r>>1;
if(check(mid)) l=mid+1,Ans=mid;
else r=mid-1;
}return 0&printf("%d\n",Ans);
}
P3400 仓鼠窝
处理出向上的高,再左右单调栈出能到达的位置,统计答案即可。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define int long long
const int N=4e3+7;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
return f?-x:x;
}
int n,m;
long long Ans;
bool vis[N][N];
int h[N][N],l[N],r[N],stc[N],sc;
signed main() {
n=read();m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch;
cin>>ch;
h[i][j]=(ch=='0')?0:h[i-1][j]+1;
}
}
for(int i=1;i<=n;i++){
sc=0;
for(int j=1;j<=m;j++){
while(sc&&h[i][stc[sc]]>=h[i][j]) sc--;
l[j]=stc[sc];stc[++sc]=j;
}
sc=0;stc[++sc]=m+1;
for(int j=m;j>=1;j--){
while(sc&&h[i][stc[sc]]>h[i][j]) sc--;
r[j]=stc[sc];stc[++sc]=j;
}
for(int j=1;j<=m;j++)Ans+=1LL*((j-l[j])*(r[j]-j)*h[i][j]);
}
printf("%lld\n",Ans);
return 0;
}
CF460C Present
算是差分吧,就是二分最小值然后差分 check 一下能不能达到最小值就行了。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define debug cout<<"Szt ak ioi\n";
#define int long long
const int Mod=1e9+7;
const int N=1e6+7,M=2e3+1;
using namespace std;
inline int read() {
int x=0,f=0;
char ch=getchar();
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+(ch&15),ch=getchar();
return f?-x:x;
}
int n,m,w,a[N],diff[N],D[N];
bool check(int mid){
int res=0,ret=0;
for(int i=1;i<=n;i++)D[i]=diff[i];
for(int i=1;i<=n;i++){
res+=D[i];
if(res>=mid) continue;
ret+=(mid-res);D[i]+=(mid-res);
if(i+w<=n) D[i+w]-=(mid-res);
res+=(mid-res);
}
return ret<=m;
}
signed main() {
int l=1e9,r=1e10,Ans=0;
n=read(),m=read(),w=read();
for(int i=1;i<=n;i++)a[i]=read(),diff[i]=a[i]-a[i-1],l=min(l,a[i]);
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) l=mid+1,Ans=mid;
else r=mid-1;
}
printf("%lld\n",Ans);
return 0;
}