BZOJ
BZOJ出新题了,赶紧去抢一血。没有数据?!Python 2B!
![这里写图片描述](https://img-blog.csdn.net/20170921205449546?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzYzNjgwOTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
重测后
5018: [Snoi2017]英雄联盟
DP,用f[i][j]表示DP到第i个物品,花费为j时最大的方案数。
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
inline char tc(void){
static char fl[10000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,10000,stdin),A==B)?EOF:*A++;
}
inline ll read(void){
ll a=0;static char c;
while((c=tc())<'0'||c>'9');
while(c>='0'&&c<='9')a=a*10+c-'0',c=tc();
return a;
}
ll m;
int mx,n,k[122],c[122],ans=2e9;
ll dp[122][242781];
int main(void){
register int i,j,l,x;
n=read(),m=read();
for(i=1;i<=n;++i)k[i]=read();
for(i=1;i<=n;mx+=k[i]*c[i],++i)c[i]=read();
dp[0][0]=1;
for(i=1;i<=n;++i)
for(j=0,x=0;j<=k[i];++j,x+=c[i])
for(l=x;l<=mx;++l){
dp[i][l]=max(dp[i][l],dp[i-1][l-x]*((j==0)?1:j));
if(dp[i][l]>=m){
ans=min(l,ans);
break;
}
}
printf("%d",ans);
return 0;
}
5017: [Snoi2017]炸弹
先刷出每个炸弹在不往右炸的情况下能往左炸到哪里,然后每个点往右炸的同时更新右端点。
注意别爆long long,细节看代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
inline char tc(void){
static char fl[10000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,10000,stdin),A==B)?EOF:*A++;
}
inline ll read(void){
ll a=0,f=1;static char c;
while((c=tc())<'0'||c>'9')c=='-'?f=-1:0;
while(c>='0'&&c<='9')a=a*10+c-'0',c=tc();
return a*f;
}
const int Mod=1000000007;
ll ans,n,x[500001],y[500001],l[500001],r[500001];
int main(void){
register int i,a;
n=read();
for(i=1;i<=n;++i)
x[i]=read(),y[i]=read();
for(i=1;i<=n;++i){
l[i]=i;
while(l[i]>1&&x[i]-x[l[i]-1]<=y[i])
l[i]=l[l[i]-1],y[i]=max(y[i],y[l[i]]-x[i]+x[l[i]-1]);
}
for(i=n;i;--i){
r[i]=i;
while(r[i]<n&&x[r[i]+1]-x[i]<=y[i])
r[i]=r[r[i]+1],l[i]=min(l[i],l[r[i]]);
}
for(i=1;i<=n;++i)
ans=(ans+(r[i]-l[i]+1)*i)%Mod;
printf("%d",ans);
return 0;
}
5019: [Snoi2017]遗失的答案
这题比较有趣吧!如果lcm%gcd!=0就直接全输出0。我们对lcm和gcd进行质因数分解。
lcm=∏Plkk,gcd=∏Pgkk
如果一个数x有用,x=∏Pakk,那么对于任意Pk,都有ak∈[gk,lk],然后我们DFS一下,把有用的数x全部刷出来。
然后有用的数就到1000以下了,我们可以通过DP先求出总方案数,然后把不含一个数的方案求出,相减就可以求解了。
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define Mod 1000000007
inline char tc(void){
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline int read(void){
int a=0;static char c;
while((c=tc())<'0'||c>'9');
while(c>='0'&&c<='9')a=a*10+c-'0',c=tc();
return a;
}
struct M{
int x,dx,dix;
M(int x=0,int dx=0,int dix=0):x(x),dx(dx),dix(dix){}
inline bool operator <(const M&a)const{
return x<a.x;
}
}que[1000];
int n,q,l,g,cnt,p[12],num[12],tot,dp[256][256],ans[1000];
bool invalid;
void resolve(void){
int x=l,y=g;
for(int i=2;i*i<=x;++i)
if(l%i==0){
while(x%i==0&&y%i==0)
x/=i,y/=i;
if(x%i==0)p[++cnt]=i;
while(x%i==0)
++num[cnt],x/=i;
}
if(x>1&&x!=y)p[++cnt]=x,++num[cnt];
return ;
}
void dfs(int now,ll sum,int dx,int dix){
if(sum>n)return ;
if(now>cnt){
que[++tot]=M(sum,dx,dix);
return ;
}
ll o=1;
for(int i=0;i<=num[now];++i,o*=p[now])
if(i==0)dfs(now+1,sum*o,dx,dix|(1<<now-1));
else if(i==num[now])dfs(now+1,sum*o,dx|(1<<now-1),dix);
else dfs(now+1,sum*o,dx,dix);
return ;
}
void solve(void){
int i,j,k,mx=(1<<cnt)-1,t;
sort(que+1,que+tot+1);
dp[0][0]=1,dp[que[1].dx][que[1].dix]=1;
for(i=2;i<=tot;++i)
for(j=mx;j>=0;--j)
for(k=mx;k>=0;--k)
(dp[j|que[i].dx][k|que[i].dix]+=dp[j][k])%=Mod;
for(int i=1;i<=tot;++i){
t=dp[mx][mx];
for(int j=0;j<=mx;j++)
for(int k=0;k<=mx;k++)
if(k!=mx||j!=mx)
if((j|que[i].dx)==mx&&(k|que[i].dix)==mx)t=(t-dp[j][k])%Mod;
ans[i]=((ll)t*500000004%Mod+Mod)%Mod,ans[i]=((ll)dp[mx][mx]-ans[i]+Mod)%Mod;
}
return ;
}
int ef(int x){
int l=1,r=tot,mid;
while(l<=r){
mid=l+r>>1;
if(que[mid].x<=x)l=mid+1;
else r=mid-1;
}
return que[l-1].x==x?l-1:0;
}
int main(void){
register int i,x;
n=read(),g=read(),l=read();
if(l%g!=0)invalid=1;
if(invalid)goto wjnsb;
resolve(),dfs(1,g,0,0),solve();
q=read();while(q--)x=read(),printf("%d\n",ans[ef(x)]);
return 0;
wjnsb:q=read();while(q--)puts("0");return 0;
}
4804: 欧拉心算
莫比乌斯反演,随便推推就出来了。
#include<cstdio>
using namespace std;
#define N 10000000
#define ll long long
inline char tc(void){
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline int read(void){
int a=0;static char c;
while((c=tc())<'0'||c>'9');
while(c>='0'&&c<='9')a=a*10+c-'0',c=tc();
return a;
}
int T,n,prim[2000000],E[N+10],cnt,t,pos;
ll ans,sum[N+10];
char p[N+10];
void pre(void){
register int i,j;
E[1]=1;
for(i=2;i<=N;++i){
if(p[i]==0)prim[++cnt]=i,E[i]=i-1;
for(j=1;j<=cnt&&(t=i*prim[j])<=N;++j){
p[t]=1;
if(i%prim[j]==0){
E[t]=E[i]*prim[j];
break;
}
E[t]=E[i]*(prim[j]-1);
}
}
for(i=1;i<=N;++i)
sum[i]=sum[i-1]+E[i];
return ;
}
int main(void){
register int i,pos;
for(pre(),T=read();T;--T){
n=read(),ans=0;
for(i=1,pos;i<=n;i=pos+1)
pos=n/(n/i),ans+=(sum[pos]-sum[i-1])*sum[n/pos];
printf("%lld\n",ans*2-sum[n]);
}
return 0;
}
3085: 反质数加强版SAPGAP
%Manchery
在反素数那题的基础上加上一个优化可以草过去
看Manchery大佬的博客吧
我的代码就是抄的
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define clr(x,y) memset(x,y,sizeof(x))
using namespace std;
#define ll long long
struct BIGINT{
int a[30];
BIGINT(void){}
BIGINT(char *s){
clr(a,0);
int i,L=strlen(s),cur=0;
for(i=L-1;i-3>=0;i-=4){
a[cur]=(s[i-3]-'0')*1000+
(s[i-2]-'0')*100+
(s[i-1]-'0')*10+
(s[i]-'0');
++cur;
}
if(i<0)return ;
if(i==0)a[cur]=s[0]-'0';
else if(i==1)a[cur]=10*(s[0]-'0')+(s[1]-'0');
else if(i==2)a[cur]=100*(s[0]-'0')+10*(s[1]-'0')+(s[2]-'0');
return ;
}
BIGINT(int x){
clr(a,0),a[0]=x;
return ;
}
inline BIGINT operator*(int x){
int i;
BIGINT tmp;
for(i=0;i<27;++i)tmp.a[i]=a[i]*x;
for(i=0;i<26;++i){
tmp.a[i+1]+=tmp.a[i]/10000;
tmp.a[i]%=10000;
}
return tmp;
}
int operator<(BIGINT p){
int i;
for(i=26;i>=0;--i){
if(a[i]<p.a[i])return 1;
if(a[i]>p.a[i])return 0;
}
return 0;
}
int operator==(BIGINT p){
int i;
for(i=26;i>=0;--i)
if(a[i]!=p.a[i])return 0;
return 1;
}
int operator<=(BIGINT p){
return *this==p||*this<p;
}
void print(void){
int cur=26;
while(cur>0&&0==a[cur])--cur;
printf("%d",a[cur]);
--cur;
while(cur>=0)printf("%04d",a[cur--]);
puts("");
return ;
}
};
int prime[]={
1, 2, 3, 5, 7,
11, 13, 17, 19, 23,
29, 31, 37, 41, 43,
47, 53, 59, 61, 67,
71, 73, 79, 83, 89,
97, 101,103,107,109,
113,127,131,137,139,
149,151,157,163,167,
173,179,181,191,193,
197,199,211,223,227,
229,233,239,241,251
};
int K[]={
1,2,2,3,3,
4,4,5,5,5,
5,5,6,6,6,
6,6,6,6,7,
7,7,7,7,7,
7,7,7,7,7,
7,7,8,8,8,
8,8,8,8,8,
8,8,8,8,8,
8,8,8,8,8,
8,8,8,8,8
};
BIGINT n,ans;
ll m,q1,maxinum;
inline void dfs(int k,BIGINT now,ll cnt,ll last){
if(cnt>maxinum||cnt==maxinum&&now<ans)
ans=now,maxinum=cnt;
if(k!=1)
last=min(last,q1/(K[k]-1));
ll tmp=cnt;
for(int i=1;i<=last;++i){
if(k==1)q1=i;
tmp+=cnt;
now=now*prime[k];
if(n<now)break;
dfs(k+1,now,tmp,i);
}
return ;
}
char s[105];
int main(void){
register int i;
scanf("%s",s),
n=BIGINT(s);
if(n==BIGINT(1))
return puts("1"),0;
BIGINT itmp=BIGINT(1);
for(;itmp<=n;)itmp=itmp*prime[++m];
dfs(1,BIGINT(1),1,2*K[m]-1-1);
ans.print();
return 0;
}
51nod
1076 2条不相交的路径
边双裸题
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline char tc(void){
static char fl[10000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,10000,stdin),A==B)?EOF:*A++;
}
inline int read(void){
int a=0;static char c;
while((c=tc())<'0'||c>'9');
while(c>='0'&&c<='9')a=a*10+c-'0',c=tc();
return a;
}
int n,m,q,tot,time,low[25100],pre[25100];
struct Edge{
int to,bridge;
Edge *next;
}e[100001],*link[52003];
inline void add(int x,int y){
e[++tot].to=y,e[tot].next=link[x],link[x]=&e[tot];
return ;
}
void dfs(int u,int fa){
low[u]=pre[u]=++time;
for(Edge *i=link[u];i;i=i->next){
if(!pre[i->to]){
dfs(i->to,u);
low[u]=min(low[i->to],low[u]);
if(pre[u]<low[i->to])
i->bridge=1;
}else if(fa!=i->to)
low[u]=min(low[u],pre[i->to]);
}
return ;
}
void dfs(int u){
pre[u]=time;
for(Edge *i=link[u];i;i=i->next){
if(i->bridge||pre[i->to])continue;
dfs(i->to);
}
return ;
}
int main(void){
register int i,x,y;
n=read(),m=read();
for(i=1;i<=m;++i)
x=read(),y=read(),add(x,y),add(y,x);
time=0;
for(i=1;i<=n;++i)
if(!pre[i])
dfs(i,0);
time=0;
memset(pre,0,sizeof(pre));
for(i=1;i<=n;++i)
if(!pre[i])
++time,dfs(i);
q=read();
while(q--){
x=read(),y=read();
if(pre[x]==pre[y])puts("Yes");
else puts("No");
}
return 0;
}
1033 骨牌覆盖 V2
轮廓线DP+矩乘快速幂
#include<cstdio>
using namespace std;
#define ll long long
#define Mod 1000000007
ll n,m,now,k[32][32],ans;
struct Y{
ll k[32][32];
Y operator *(Y a){
Y b;
for(int i=0;i<(1<<n);++i)
for(int j=0;j<(1<<n);++j){
b.k[i][j]=0;
for(int l=0;l<(1<<n);++l)
(b.k[i][j]+=k[i][l]*a.k[l][j])%=Mod;
}
return b;
}
}o;
struct M{
ll k[32];
M operator *(Y a){
M b;
for(int i=0;i<1<<n;++i)
b.k[i]=0;
for(int i=0;i<(1<<n);++i)
for(int l=0;l<(1<<n);++l)
(b.k[i]+=k[l]*a.k[i][l])%=Mod;
return b;
}
}l;
void dfs(int x,int sum){
if(x>n){
++k[now][sum];
return ;
}
if(sum&(1<<x-1))
dfs(x+1,sum-(1<<x-1));
else
dfs(x+1,sum+(1<<x-1));
if(x!=n&&!(sum&(1<<x-1))&&!(sum&(1<<x)))
dfs(x+2,sum);
return ;
}
M ksm(Y a,int b){
M s;
for(int i=1;i<1<<n;++i)
s.k[i]=0;
s.k[0]=1;
while(b){
if(b&1)s=s*a;
a=a*a;
b>>=1;
}
return s;
}
int main(void){
register int i,j;
scanf("%d%d",&m,&n);
for(now=0;now<1<<n;++now)
dfs(1,now);
for(i=0;i<1<<n;++i)
for(j=0;j<1<<n;++j)
o.k[i][j]=k[i][j];
l=ksm(o,m);
printf("%lld",l.k[0]);
return 0;
}