算是今年多校比较友好的一场比赛了
1002
http://acm.hdu.edu.cn/showproblem.php?pid=4961
解题思路:题意看上去比较绕,实际上就是求对于每个a[i]其左右两边最靠近它的且是它的倍数的数各是多少,首先不难想到预处理出1-1e5的数的约数,然后我们从左到右扫一遍每次更新当前数字的所有约数的所求位置,同时当前位置的b[i]也就确定下来了,同理从右向左扫一遍处理出c[i]数组,然后相乘求和即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <vector>
#include <bitset>
#include <cmath>
#include <utility>
#define Maxn 100005
#define Inf 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PI acos(-1.0)
#define LL long long
#define make_pair MP
#define re freopen("in.txt","r",stdin)
#define wr freopen("out.txt","w",stdout)
using namespace std;
LL a[Maxn],b[Maxn],c[Maxn];
int pos[Maxn];
vector<int> yueshu[Maxn+5];
void get_yueshu()
{
for(int i=0;i<Maxn;i++)
yueshu[i].clear();
for(int i=1;i<Maxn;i++)
for(int j=i;j<Maxn;j+=i)
yueshu[j].push_back(i);
}
void solve(int n)
{
LL ans=0;
memset(pos,0,sizeof(pos));
for(int i=1;i<=n;i++)
{
int u=a[i];
int k=pos[u]==0?i:pos[u];
b[i]=a[k];
int s=yueshu[u].size();
for(int j=0;j<s;j++)
pos[yueshu[u][j]]=max(pos[yueshu[u][j]],i);
}
memset(pos,Inf,sizeof(pos));
for(int i=n;i>=1;i--)
{
int u=a[i];
int k=pos[u]==Inf?i:pos[u];
c[i]=a[k];
int s=yueshu[u].size();
for(int j=0;j<s;j++)
pos[yueshu[u][j]]=min(pos[yueshu[u][j]],i);
}
for(int i=1;i<=n;i++)
ans+=b[i]*c[i];
printf("%I64d\n",ans);
}
int main()
{
int n;
//re;
//wr;
get_yueshu();
while(~scanf("%d",&n),n)
{
for(int i=1;i<=n;i++)
scanf("%I64d",a+i);
solve(n);
}
return 0;
}
1006
http://acm.hdu.edu.cn/showproblem.php?pid=4965
解题思路:矩阵快速幂,但是不能直接求,C=A*B,C^(N*N))就是(A*B)^(N*N)即A*B*A*B...*A*B因为矩阵乘法满足结合律而B*A最大是一个6*6的矩阵那么就是A*(B*A)^(N*N-1)*B,中间部分矩阵快速幂即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <vector>
#include <bitset>
#include <cmath>
#include <utility>
#define Maxn 1005
#define Inf 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PI acos(-1.0)
#define make_pair MP
#define LL long long
#define re freopen("in.txt","r",stdin)
#define wr freopen("out.txt","w",stdout)
using namespace std;
struct Matrix
{
int val[7][7];
int m,n;
Matrix()
{
m=n=0;
memset(val,0,sizeof(val));
}
friend Matrix operator *(Matrix &A,Matrix &B)
{
Matrix tmp;
for(int i=1;i<=A.m;i++)
for(int j=1;j<=B.n;j++)
for(int k=1;k<=A.n;k++)
{
tmp.val[i][j]+=A.val[i][k]*B.val[k][j];
tmp.val[i][j]%=6;
}
tmp.m=A.m;tmp.n=B.n;
return tmp;
}
friend Matrix operator ^(Matrix &x,int n)
{
Matrix tmp;
tmp.m=x.m;tmp.n=x.n;
for(int i=1;i<=x.m;i++)
tmp.val[i][i]=1;
while(n)
{
if(n&1)
tmp=tmp*x;
x=x*x;
n>>=1;
}
return tmp;
}
};
int mp1[Maxn][7],mp2[7][Maxn],mp3[Maxn][7],mp4[Maxn][Maxn];
int i,j,k,N,K,ans;
void mul1(Matrix &C)
{
for(int i=1;i<=K;i++)
for(int j=1;j<=K;j++)
{
for(int k=1;k<=N;k++)
{
C.val[i][j]+=mp2[i][k]*mp1[k][j];
C.val[i][j]%=6;
}
}
}
void mul2(Matrix C)
{
for(int i=1;i<=N;i++)
for(int j=1;j<=K;j++)
for(int k=1;k<=K;k++)
{
mp3[i][j]+=mp1[i][k]*C.val[k][j];
mp3[i][j]%=6;
}
}
void mul3()
{
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
for(int k=1;k<=K;k++)
{
mp4[i][j]+=mp3[i][k]*mp2[k][j];
mp4[i][j]%=6;
}
}
int main()
{
//re;
//wr;
while(~scanf("%d%d",&N,&K),N+K)
{
Matrix C;
ans=0;
memset(mp1,0,sizeof(mp1));
memset(mp2,0,sizeof(mp2));
memset(mp3,0,sizeof(mp3));
memset(mp4,0,sizeof(mp4));
for(i=1;i<=N;i++)
for(j=1;j<=K;j++)
scanf("%d",&mp1[i][j]);
for(i=1;i<=K;i++)
for(j=1;j<=N;j++)
scanf("%d",&mp2[i][j]);
mul1(C);
C.m=C.n=K;
C=C^(N*N-1);
mul2(C);
mul3();
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
ans+=mp4[i][j]%6;
printf("%d\n",ans);
}
return 0;
}
1007
http://acm.hdu.edu.cn/showproblem.php?pid=4966
解题思路:最小树形图模板题,将a课程的b等级与c课程的d等级连一条权值为w的边,同时同一课程的高等级向低等级连一条权值为0的边,所有课程的1等级向0号点连一条权值为0的边,跑一下最小树形图的模板即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <vector>
#include <bitset>
#include <cmath>
#include <utility>
#define Maxn 505
#define Maxm 10005
#define Inf 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PI acos(-1.0)
#define make_pair MP
#define LL long long
#define re freopen("in.txt","r",stdin)
#define wr freopen("out.txt","w",stdout)
using namespace std;
struct Edge
{
int s,e,w;
};
Edge edge[Maxm];
int pre[Maxm],vis[Maxm],id[Maxm],in[Maxm],L;
void add(int s,int e,int w)
{
edge[L].s=s;
edge[L].e=e;
edge[L++].w=w;
}
int zhuliu(int root,int n,int m,Edge edge[])
{
int res=0,s,e;
while(1)
{
for(int i=0;i<n;i++)
in[i]=Inf;
for(int i=0;i<m;i++)
if(edge[i].s!=edge[i].e&&edge[i].w<in[edge[i].e])
{
pre[edge[i].e]=edge[i].s;
in[edge[i].e]=edge[i].w;
}
for(int i=0;i<n;i++)
if(i!=root&&in[i]==Inf)
return -1;
int tn=0;
memset(id,-1,sizeof(id));
memset(vis,-1,sizeof(vis));
in[root]=0;
for(int i=0;i<n;i++)
{
res+=in[i];
e=i;
while(vis[e]!=i&&id[e]==-1&&e!=root)
{
vis[e]=i;
e=pre[e];
}
if(e!=root&&id[e]==-1)
{
for(s=pre[e];s!=e;s=pre[s])
id[s]=tn;
id[e]=tn++;
}
}
if(tn==0)
break;
for(int i=0;i<n;i++)
if(id[i]==-1)
id[i]=tn++;
for(int i=0;i<m;i++)
{
e=edge[i].e;
edge[i].s=id[edge[i].s];
edge[i].e=id[edge[i].e];
if(edge[i].s!=edge[i].e)
edge[i].w-=in[e];
}
n=tn;
root=id[root];
}
return res;
}
int main()
{
int m,n,a[55],c,d,l1,l2,w,N;
//re;wr;
while(~scanf("%d%d",&n,&m),m+n)
{
N=L=0;
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
add(a[i-1]+1,0,0);
scanf("%d",a+i);
for(int j=2;j<=a[i];j++)
add(a[i-1]+j,a[i-1]+j-1,0);
a[i]+=a[i-1];
}
N=a[n]+1;
while(m--)
{
scanf("%d%d%d%d%d",&c,&l1,&d,&l2,&w);
int s=l1==0?0:a[c-1]+l1;int e=l2==0?0:a[d-1]+l2;
add(s,e,w);
}
printf("%d\n",zhuliu(0,N,L,edge));
}
return 0;
}
1008
http://acm.hdu.edu.cn/showproblem.php?pid=4967
解题思路:
给定一些入栈,出栈,弹出栈顶元素的操作和他们的时间戳,每次询问已经输入过的操作中时间戳在询问之前的最近的那个应该被弹出的元素是什么,我们把入栈操作当做在其时间戳位置+1,出栈操作当做在其时间戳位置-1,问题转化为求最小的i,使得sum[x]-sum[i-1]>0,x是询问时间戳位置。我们用线段树维护两个值区间和以及区间最大后缀的值,每次先向右子树查找,如果该区间的最大后缀值加上sigma(tree[i],R+1,x)大于0就说明在这个区间内,否则向左子树查找
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <vector>
#include <bitset>
#include <cmath>
#include <utility>
#define Maxn 50005
#define Maxm 10005
#define Inf 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1
#define PI acos(-1.0)
#define make_pair MP
#define LL long long
#define re freopen("in.txt","r",stdin)
#define wr freopen("out.txt","w",stdout)
using namespace std;
int sum[Maxn<<2],rmax[Maxn<<2];
int ans;
struct Node
{
int x,t,id;
char op[10];
Node()
{
x=t=id=0;
memset(op,'\0',sizeof(op));
}
};
bool cmp1(Node a,Node b)
{
return a.t<b.t;
}
bool cmp2(Node a,Node b)
{
return a.id<b.id;
}
Node cmd[Maxn];
void init(int n)
{
for(int i=0;i<n;i++)
{
cmd[i].x=cmd[i].t=cmd[i].id=0;
memset(cmd[i].op,'\0',sizeof(cmd[i].op));
}
memset(sum,0,sizeof(sum));
memset(rmax,-Inf,sizeof(rmax));
}
int read()
{
int res=0;
while(1)
{
char ch=getchar();
if(ch>='0'&&ch<='9')
res=res*10+ch-'0';
else
break;
}
return res;
}
void push_up(int rt)
{
sum[rt]=sum[ls]+sum[rs];
rmax[rt]=max(rmax[rs],sum[rs]+rmax[ls]);
}
void update(int pos,int x,int l,int r,int rt)
{
if(l==r)
{
sum[rt]=rmax[rt]=x;
return ;
}
int m=(l+r)>>1;
if(pos<=m)
update(pos,x,lson);
else
update(pos,x,rson);
push_up(rt);
}
int get_pos(int l,int r,int rt,int k)
{
if(l==r)
return l;
int m=(l+r)>>1;
if(k+rmax[rs]>0)
return get_pos(rson,k);
else
return get_pos(lson,k+sum[rs]);
}
void query(int L,int R,int &k,int l,int r,int rt)
{
if(ans)
return ;
if(L<=l&&R>=r)
{
if(rmax[rt]+k<=0)//k值用来维护sigma(sum[i],r+1,R)
k+=sum[rt];
else
ans=get_pos(l,r,rt,k);
return ;
}
int m=(l+r)>>1;
if(R>m)
query(L,R,k,rson);
if(L<=m)
query(L,R,k,lson);
return ;
}
int main()
{
int ncase=1;
int n,id[Maxn];
//re;wr;
while(~scanf("%d",&n),n)
{
init(n);
memset(id,0,sizeof(id));
for(int i=0;i<n;i++)
{
scanf("%s",cmd[i].op);
int len=strlen(cmd[i].op);
cmd[i].op[len]='\0';
getchar();
if(cmd[i].op[1]=='u')
cmd[i].x=read(),cmd[i].t=read();
else if(cmd[i].op[1]=='o')
cmd[i].t=read();
else
cmd[i].t=read();
cmd[i].id=i;
}
sort(cmd,cmd+n,cmp1);
for(int i=0;i<n;i++)
cmd[i].t=i+1,id[cmd[i].t]=cmd[i].id;
sort(cmd,cmd+n,cmp2);
printf("Case #%d:\n",ncase++);
for(int i=0;i<n;i++)
{
if(cmd[i].op[1]=='u')
update(cmd[i].t,1,1,n,1);
else if(cmd[i].op[1]=='o')
update(cmd[i].t,-1,1,n,1);
else
{
ans=0;
int k=0;
query(1,cmd[i].t,k,1,n,1);
printf("%d\n",ans?cmd[id[ans]].x:-1);
}
}
}
return 0;
}
解题思路:贪心即可,要高GPA就是让尽量多的科目处于恰好能拿到高绩点的最低分数,要低GPA就是让尽可能多的科目处在低绩点的最高分数上
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <vector>
#include <bitset>
#include <cmath>
#include <utility>
#define Maxn 1000005
#define Inf 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define make_pair MP
#define PI acos(-1.0)
#define re freopen("in.txt","r",stdin)
#define wr freopen("out.txt","w",stdout)
using namespace std;
int l[]={60,70,75,80,85};
int r[]={69,74,79,84,100};
double gpa[]={2.0,2.5,3.0,3.5,4.0};
int main()
{
int m,n,t,sum,now,ans1[5],ans2[5];
double a,b;
re;
wr;
scanf("%d",&t);
while(t--)
{
a=b=0.0;
memset(ans1,0,sizeof(ans1));
memset(ans2,0,sizeof(ans2));
scanf("%d%d",&n,&m);
sum=m*n;
now=m;
for(int i=0;i<5;i++)
{
int k=now;
while(k)
{
int tmp=k*r[i];
if((now-k)*100<sum-tmp)
k--;
else
{
ans1[i]=k;
break;
}
}
sum-=k*r[i];
now-=k;
}
sum=m*n;
now=m;
for(int i=4;i>=0;i--)
{
int k=now;
while(k)
{
int tmp=k*l[i];
if((now-k)*60>sum-tmp)
k--;
else
{
ans2[i]=k;
break;
}
}
sum-=k*l[i];
now-=k;
}
for(int i=0;i<5;i++)
a+=ans1[i]*gpa[i],b+=ans2[i]*gpa[i];
a/=m;
b/=m;
printf("%.4lf %.4lf\n",a,b);
}
return 0;
}
1010
http://acm.hdu.edu.cn/showproblem.php?pid=4969
解题思路:数学积分,汉纸和妹纸要处在同一条直线上就是两人的角速度要时刻相同,令vx表示汉纸的切向速度,vy表示汉纸的径向速度,则vx/r=v1/R,v1^2=vx^2+vy^2,vy=sqrt(v1^2-(v2*r/R)^2)=dr/dt,令t0表示汉纸跑的时间积分得t0=R/v1*arcsin(v1/v2),判断下t0时间内能跑的距离是否大于d即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <vector>
#include <bitset>
#include <cmath>
#include <utility>
#define Maxn 50005
#define Maxm 10005
#define Inf 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ls rt<<1
#define rs rt<<1|1
#define PI acos(-1.0)
#define make_pair MP
#define LL long long
#define re freopen("in.txt","r",stdin)
#define wr freopen("out.txt","w",stdout)
using namespace std;
int main()
{
int T;
scanf("%d",&T);
double v1,v2,R,D;
while(T--)
{
scanf("%lf%lf%lf%lf",&v1,&v2,&R,&D);
double ans=R/v1*(asin(v1/v2));
if(ans*v2>D)
printf("Why give up treatment\n");
else
printf("Wake up to code\n");
}
return 0;
}
1011
http://acm.hdu.edu.cn/showproblem.php?pid=4970
解题思路:我是直接上线段树的,求怪物到终点的伤害是否大于h即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <stack>
#include <deque>
#include <vector>
#include <bitset>
#include <cmath>
#include <utility>
#define Maxn 100005
#define Inf 0x3f3f3f3f
#define lowbit(x) x&(-x)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PI acos(-1.0)
#define make_pair MP
#define LL long long
#define re freopen("in.txt","r",stdin)
#define wr freopen("out.txt","w",stdout)
using namespace std;
LL tree[Maxn<<2];
int cover[Maxn<<2];
void push_up(int rt)
{
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void push_down(int rt,int m)
{
if(cover[rt])
{
cover[rt<<1]+=cover[rt];
cover[rt<<1|1]+=cover[rt];
tree[rt<<1]+=(m-(m>>1))*cover[rt];
tree[rt<<1|1]+=(m>>1)*cover[rt];
cover[rt]=0;
}
}
void update(int L,int R,int x,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
tree[rt]+=x*(r-l+1);
cover[rt]+=x;
return ;
}
push_down(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
update(L,R,x,lson);
if(R>m)
update(L,R,x,rson);
push_up(rt);
}
LL query(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r)
return tree[rt];
push_down(rt,r-l+1);
int m=(l+r)>>1;
LL ans=0;
if(L<=m)
ans+=query(L,R,lson);
if(R>m)
ans+=query(L,R,rson);
return ans;
}
int main()
{
int n,m,l,r,d,k,x,ans;
LL h;
//re;
//wr;
while(~scanf("%d",&n)&&n)
{
ans=0;
memset(tree,0,sizeof(tree));
memset(cover,0,sizeof(cover));
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&l,&r,&d);
update(l,r,d,1,n,1);
}
scanf("%d",&k);
while(k--)
{
scanf("%I64d%d",&h,&x);
ans+=query(x,n,1,n,1)<h?1:0;
}
printf("%d\n",ans);
}
return 0;
}
其实模仿树状数组区间修改的做法,用一个数组记录下后缀和更快
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std ;
typedef __int64 ll ;
ll ak[100005],sum[100005] ;
int main()
{
int n ;
while(~scanf("%d",&n),n)
{
int m,k ;
scanf("%d",&m) ;
memset(ak,0,sizeof(ak)) ;
memset(sum,0,sizeof(sum)) ;
while(m--)
{
int L,R,D ;
scanf("%d%d%d",&L,&R,&D) ;
ak[L]+=(ll)D ;
ak[R+1]-=(ll)D ;
}
for(int i=1 ;i<=n ;i++)
sum[i]=sum[i-1]+ak[i] ;
for(int i=n-1 ;i>0 ;i--)
sum[i]+=sum[i+1] ;
scanf("%d",&k) ;
int ans=0 ;
while(k--)
{
int x ;
ll h ;
scanf("%I64d%d",&h,&x) ;
if(sum[x]<h)ans++ ;
}
printf("%d\n",ans) ;
}
return 0 ;
}