8.8

ABC417_D,luogu P9401 ,ABC409_F
ABC417_D
赛时想的是记录当开始时初始值在不同区间时所对的答案
对于每一次收到礼物,会产生三个区间
1.p[i]>=now 对于区间0到p[i]增加一个a[i]
2.p[i]<now&&now>=b[i] 对于区间max(p[i]+1,b[i])到inf减去一个b[i]
3.p[i]<now&&now<b[i] 对于区间p[i]+1到b[i]-1设为0
但是这么做会让程序十分复杂赛时没有调出来,而且对于初始值极大的问题就束手无策了
考虑动态规划,注意数据范围,所有涉及心情变化的值均小于等于500
那么可以说明,当一个1000以内的心情加入运算时,这个值一定会持续保留在1000以内
设计dp[i][j]表示第i次运算前,当前心情为j,最后会达到的心情
对于初始值极大的问题,保留dp的第一维(也就是第i次运算时),二分需要减去多少才会达到1000以内
然后在dp的当前次运算中取答案即可,时间复杂度为O(mn + q log n)
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=1e4+5;
const int maxm=1005;
const int m=1000;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
int p[maxn],a[maxn],b[maxn];
int dp[maxn][m];
int sum[maxn];
int n,q;
int main(){
read(n);
for(int i=1;i<=n;i++){
read(p[i]),read(a[i]),read(b[i]);
sum[i]=sum[i-1]+b[i];
}
for(int i=0;i<=m;i++) dp[n+1][i]=i;
for(int i=n;i>=1;i--){
for(int j=0;j<=m;j++){
if(p[i]>=j) dp[i][j]=dp[i+1][j+a[i]];
else dp[i][j]=dp[i+1][max(j-b[i],0)];
}
}
read(q);
int in;
while(q--){
read(in);
int i=lower_bound(sum,sum+n+1,in-m)-sum;
//cout<<i<<" ans=";
if(i==n+1) printf("%d\n",in-sum[n]);
else printf("%d\n",dp[i+1][in-sum[i]]);
}
return 0;
}
//^o^
luogu P9401
先顺道去学了个binary_gcd,这篇题解挺好的
附上我的代码(luogu P5435)
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=5005;
const int mod=998244353;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
int a[maxn],b[maxn];
int n;
int gcd(int x,int y){
int xi=__builtin_ctz(x),yi=__builtin_ctz(y);
int z=min(xi,yi);
y>>=yi;
int temp;
while(y){
x>>=xi;
temp=y-x;
xi=__builtin_ctz(temp);
y=(y>x ? x : y);
x=(temp<0 ? -temp : temp);
}
return x<<z;
}
int main(){
read(n);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++) read(b[i]);
LL ans,p;
for(int i=1;i<=n;i++){
ans=0,p=i;
for(int j=1;j<=n;j++){
ans+=p*gcd(a[i],b[j]);
ans%=mod;
p=p*i%mod;
}
printf("%lld\n",ans);
}
return 0;
}
//^o^
因为a的数据范围较小,把b按照a放到桶中
先特判全选b的情况,否则如果选了至少一个a,答案一定在5e5以内,直接枚举答案即可
对答案的验证:如果ans|a[i]选择a[i],否则选b[i]
既然已经建桶了,用st维护一下区间gcd即可
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
const int maxlog=20;
const int maxm=5e5;
void read(LL& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
LL gcd(LL x,LL y){
if((!x)|(!y)) return x|y;
int xi=__builtin_ctzll(x),yi=__builtin_ctzll(y);
int z=min(xi,yi);
y>>=yi;
LL temp;
while(y){
x>>=xi;
temp=y-x;
xi=__builtin_ctzll(temp);
y=(y>x ? x : y);
x=(temp<0 ? -temp : temp);
}
return x<<z;
}
LL st[21][maxm+5];
LL n;
void init_st(){
for(int i=1;i<=maxlog;i++){
for(int l=1,r=(1<<i);r<=maxm;l++,r++){
st[i][l]=gcd(st[i-1][l],st[i-1][l+(1<<(i-1))]);
}
}
}
LL query(int l,int r){
int i=log2(r-l+1);
return gcd(st[i][l],st[i][r-(1<<i)+1]);
}
int main(){
read(n);
LL a,b;
for(int i=1;i<=n;i++){
read(a),read(b);
st[0][a]=gcd(st[0][a],b);
}
init_st();
LL t=query(1,maxm);
for(int i=maxm;i>t;i--){
LL ans=0;
for(int j=i;j<=maxm;j+=i){
ans=gcd(ans,query(j-i+1,j-1));
if(ans%i) break;
}
if(maxm%i) ans=gcd(ans,query(maxm/i*i+1,maxm));
if(ans%i==0){
printf("%d",i);
return 0;
}
}
printf("%lld",t);
return 0;
}
//^o^
ABC409_F
我为什么会留一道水题
评定为中模拟一道
呃,建个优先队列保存点的距离,再建个dsu保存连通块就好
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
#define abs(x) ((x)<0 ? -(x) : (x))
using namespace std;
typedef long long LL;
const int maxn=3005;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
struct edge{
int a,b;
LL dis;
edge(){ }
edge(int ai,int bi);
bool operator<(edge a)const;
};
int x[maxn],y[maxn];
int cnt=0;
edge::edge(int ai,int bi){
a=ai,b=bi,dis=abs(x[ai]-x[bi])+abs(y[ai]-y[bi]);
}
bool edge::operator<(edge a)const{
return dis>a.dis;
}
int f[maxn];
int find_f(int u){
if(f[u]==u) return u;
else return f[u]=find_f(f[u]);
}
void merge_f(int u,int v){
int x=find_f(u),y=find_f(v);
f[x]=y;
}
priority_queue<edge> q;
void add_dot(int xi,int yi){
++cnt;
x[cnt]=xi,y[cnt]=yi;
f[cnt]=cnt;
for(int i=1;i<cnt;i++){
q.push(edge(i,cnt));
}
}
LL merge_dot(){
while((!q.empty())&&(find_f(q.top().a)==find_f(q.top().b))){
q.pop();
}
if(q.empty()) return -1;
LL d=q.top().dis;
while((!q.empty())&&q.top().dis==d){
edge e=q.top();
q.pop();
if(find_f(e.a)==find_f(e.b)) continue;
merge_f(e.a,e.b);
}
return d;
}
int n,t;
int main(){
read(n),read(t);
int xi,yi;
for(int i=1;i<=n;i++){
read(xi),read(yi);
add_dot(xi,yi);
}
while(t--){
int op;
read(op);
if(op==1){
read(xi),read(yi);
add_dot(xi,yi);
}
else if(op==2){
printf("%lld\n",merge_dot());
}
else{
read(xi),read(yi);
if(find_f(xi)==find_f(yi)){
printf("Yes\n");
}
else{
printf("No\n");
}
}
}
return 0;
}
//^o^

浙公网安备 33010602011771号