您的位置:首页 > 其它

Codeforces contest 295 recordings

2017-07-30 17:42 375 查看

A

貌似有人用线段树做了…其实没必要 由于每次增加的是区间,而查询只是在最后进行一次,可以考虑在l处+1,r+1处-1,然后用前缀和的方式从头到尾扫一遍,比线段树还快。 如果是线段树的话,也应该最后再把lazy标记pushdown,可以提高效率。 codeforces816B也是同样的思路。

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=120005;
LL init
,l
,r
,d
,ope
,nar
;
int main() {
int n,m,k,a,b;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) scanf("%I64d",&init[i]);
for(int i=1;i<=m;i++) scanf("%I64d%I64d%I64d",&l[i],&r[i],&d[i]);
for(int i=1;i<=k;i++) {
scanf("%d%d",&a,&b);
ope[a]++;
ope[b+1]--;
}
for(int i=1;i<=m;i++) {
ope[i]+=ope[i-1];
nar[l[i]]+=d[i]*ope[i];
nar[r[i]+1]-=d[i]*ope[i];
}
for(int i=1;i<=n;i++) nar[i]+=nar[i-1];
for(int i=1;i<=n;i++) printf("%I64d ",nar[i]+init[i]);
return 0;
}


B

题意是逐个删除点,借用zzy大爷的说法:遇难则反 反过来操作,每次动态加入节点,然后用Floyd的思路维护距离和,注意顺序!!! 先更新新节点和原有节点之间的最短路,才能再把新节点当成中转节点更新原有节点内的最短路!

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=505;
LL G

,ans
;
int ord
,n;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) scanf("%I64d",&G[i][j]);
for(int i=1;i<=n;i++) scanf("%d",&ord[i]);
for(int i=n;i>=1;i--) {
for(int j=i;j<=n;j++)
for(int k=i;k<=n;k++) G[ord[k]][ord[i]]=min(G[ord[k]][ord[i]],G[ord[k]][ord[j]]+G[ord[j]][ord[i]]);
for(int j=i;j<=n;j++)
for(int k=i;k<=n;k++) G[ord[i]][ord[k]]=min(G[ord[i]][ord[k]],G[ord[i]][ord[j]]+G[ord[j]][ord[k]]);
for(int j=i+1;j<=n;j++)
for(int k=i+1;k<=n;k++) G[ord[j]][ord[k]]=min(G[ord[j]][ord[i]]+G[ord[i]][ord[k]],G[ord[j]][ord[k]]);
for(int j=i;j<=n;j++)
for(int k=i;k<=n;k++) ans[i]+=G[ord[j]][ord[k]];
}
for(int i=1;i<=n;i++)  printf("%I64d ",ans[i]);
printf("\n");
return 0;
}


C

第一眼就看出是动态规划,dp[i][j][k][l]表示第i步原来河岸仍有j个50kg的人,k个100kg的人,l为1则船在对岸,为0船在此岸。 然后动规即可,注意i要取到200为宜,注意边界,注意及时取模…

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=51;
const LL mod=1e9+7;
int n,k,n1=0,n2=0;
LL dp[202]

[2],C

;//dp[st][l1][l2][boat] boat=0->this;1->oppo l1,l2:this side
int main() {
int x;
scanf("%d%d",&n,&k);
k/=50;
for(int i=1;i<=n;i++) {
scanf("%d",&x);
if(x==50) n1++;
else n2++;
}
for(int i=0;i<=n;i++) C[i][0]=1,C[i][i]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<i;j++) {
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
dp[0][n1][n2][0]=1;
for(int st=0;st<=200;st++) {
if(dp[st][0][0][1]) {
printf("%d\n%I64d\n",st,dp[st][0][0][1]);
return 0;
}
for(int a1=0;a1<=n1;a1++) {
for(int a2=0;a2<=n2;a2++) {
if(dp[st][a1][a2][0]) {
for(int u=0;u<=a1;u++) {
if(u>k) break;
for(int v=0;v<=a2;v++) {
if(u+v*2>k) break;
if(u+v==0) continue;
dp[st+1][a1-u][a2-v][1]+=(C[a2][v]*(dp[st][a1][a2][0]*C[a1][u])%mod)%mod;
dp[st+1][a1-u][a2-v][1]%=mod;
}
}
}
if(dp[st][a1][a2][1]) {
for(int u=0;u<=n1-a1;u++) {
if(u>k) break;
for(int v=0;v<=n2-a2;v++) {
if(u+v*2>k) break;
if(u+v==0) continue;
dp[st+1][a1+u][a2+v][0]+=(C[n2-a2][v]*(dp[st][a1][a2][1]*C[n1-a1][u])%mod)%mod;
dp[st+1][a1+u][a2+v][0]%=mod;
}
}
}
}
}
}
printf("-1\n0\n");
return 0;
}


D

动态规划水过,up[i][j]记录第i行两个黑格相距离为j是上方不递减的方案数,down[i][j]记录第i行距离为j,i+1行取的距离小于j时的方案数,即可水过.

注意及时取模,且统计答案时要注意hole可以左右平移.

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=2001;
const LL mod=1e9+7;
LL up

,down

,he
;
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=2;i<=m;i++) up[1][i]=1;
for(int i=2;i<=n;i++) {
for(int j=2;j<=m;j++) up[i][j]=(up[i][j-1]+up[i-1][j])%mod;
for(int j=2;j<=m;j++) up[i][j]=(up[i][j]+up[i][j-1])%mod;
for(int j=2;j<=m;j++) up[i][j]=(up[i][j]+1)%mod;
}
for(int i=2;i<=m;i++) down
[i]=1;
for(int i=n-1;i>=1;i--) {
for(int j=2;j<=m;j++) down[i][j]=(down[i][j-1]+up[n-i][j])%mod;
for(int j=2;j<=m;j++) down[i][j]=(down[i][j]+down[i][j-1])%mod;
for(int j=2;j<=m;j++) down[i][j]=(down[i][j]-up[n-i][j]+1)%mod;
}
LL ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) ans=(ans+((up[i][j]*down[i][j])%mod*(m-j+1))%mod)%mod;
printf("%I64d\n",ans);
}


E

线段树更改,先全部读进来离散化,然后操作 我们在线段树中维护以下值: num:该区间有多少个点。 sum:该区间点的横坐标之和。 ans :该区间每一对点的距离之和。 有了上面的量,下面关键的一点就是合并,其实很容易,设当前区间为t[p],其左子树为t[ls],右子树为[rs],则: t[p].sum=t[ls].sum+t[rs].sum t[p].num=t[ls].num+t[rs].num t[p].ans=t[rs].sumt[ls].num-t[rs].numt[ls].sum+t[ls].ans+t[rs].ans 貌似Anoxx是在线离散的,妙啊dalao.

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=110000;
LL init
,tab[N*2],ope
[3],ch
,h
,num[N*8],sum[N*8],ans[N*8],nn,ss,aa;
bool ini[N*2];
int sz=0;
inline void Update(int x,int l,int r) {
if(l==r) return;
int lc=(x<<1),rc=lc+1;
sum[x]=sum[lc]+sum[rc];
num[x]=num[lc]+num[rc];
ans[x]=ans[lc]+ans[rc]+num[lc]*sum[rc]-num[rc]*sum[lc];
}
inline void Build(int x,int l,int r) {
if(l==r) {
if(ini[l]) {
num[x]=1;sum[x]=tab[l];ans[x]=0;
}
return;
}
int mid=(l+r)>>1,lc=(x<<1),rc=lc+1;
Build(lc,l,mid);
Build(rc,mid+1,r);
Update(x,l,r);
}
inline void Insert(int x,int l,int r,int pos,int tp) {
if(l==r) {
if(tp==1) {
num[x]=1;sum[x]=tab[l];ans[x]=0;
} else num[x]=sum[x]=ans[x]=0;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) Insert(x<<1,l,mid,pos,tp);
else Insert(x<<1|1,mid+1,r,pos,tp);
Update(x,l,r);
}
inline void Query(int x,int l,int r,int a,int b) {
if(l>r) return;
if(l==a&&r==b) {
aa=aa+ans[x]+nn*sum[x]-num[x]*ss;
nn+=num[x];ss+=sum[x];
return;
}
if(l==r) return;
int mid=(l+r)>>1;
if(b<=mid) Query(x<<1,l,mid,a,b);

991b
else if(a>mid) Query(x<<1|1,mid+1,r,a,b);
else Query(x<<1,l,mid,a,mid),Query(x<<1|1,mid+1,r,mid+1,b);
}
int main() {
int n,q;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%I64d",&init[i]);
tab[i]=ch[i]=h[i]=init[i];
}
sz=n;
scanf("%d",&q);
for(int i=1;i<=q;i++) {
scanf("%I64d%I64d%I64d",&ope[i][0],&ope[i][1],&ope[i][2]);
if(ope[i][0]==1) {
ch[ope[i][1]]+=ope[i][2];
tab[++sz]=ch[ope[i][1]];
}
}
sort(init+1,init+n+1);
sort(tab+1,tab+sz+1);
unique(tab+1,tab+sz+1);
for(int i=1;i<=sz;i++) if(tab[i]>tab[i+1]) sz=i;
int p=1;
for(int i=1;i<=n;i++) {
while(tab[p]!=init[i]&&p<=sz) p++;
ini[p]=1;
}
Build(1,1,sz);
int l,r;
for(int i=1;i<=q;i++) {
if(ope[i][0]==2) {
l=std::lower_bound(tab+1,tab+sz+1,ope[i][1])-tab;
while(tab[l]<ope[i][1]&&l<=sz) l++;
if(l==0) l=1;
if(l>sz) {
printf("0\n");
continue;
}
r=std::lower_bound(tab+1,tab+sz+1,ope[i][2])-tab;
if(r>sz) r=sz;
while(tab[r]>ope[i][2]&&r>=1) r--;
if(r<=0) {
printf("0\n");
continue;
}
nn=ss=aa=0;
Query(1,1,sz,l,r);
printf("%I64d\n",aa);
} else {
l=std::lower_bound(tab+1,tab+sz+1,h[ope[i][1]])-tab;
h[ope[i][1]]+=ope[i][2];
r=std::lower_bound(tab+1,tab+sz+1,h[ope[i][1]])-tab;
Insert(1,1,sz,l,-1);
Insert(1,1,sz,r,1);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: