大力施工......(10/13)剩下的三个题好像不太能写啊?
A.Palindrome(hdu6230)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6230
首先用Manacher处理出所有的回文半径,然后可以得到每个点覆盖的范围,问题转换成了,有多少对点,满足,i能覆盖j而且j也能覆盖i,我们按照回文半径从大到小进行排序,然后用线段树进行维护,然后每次查询当前点能覆盖的范围有多少点即可,更新答案,最后将该点更新到线段树上。
代码:
#include
using namespace std;
typedef long long ll;
const int MAXN=5e5+5;
char Ma[MAXN];
int Mp[MAXN];
void Manacher(int len)
{
int l=len;
Ma[0]='$';
Ma[l]=0;
int mx=0,id=0;
for(int i=0;ii?min(Mp[2*id-i],mx-i):1;
while(Ma[i+Mp[i]]==Ma[i-Mp[i]])Mp[i]++;
if(i+Mp[i]>mx)
{
mx=i+Mp[i];
id=i;
}
}
}
struct node
{
int id,r;
node(int _id=0,int _r=0):id(_id),r(_r){}
bool operator <(const node &a)const
{
return r>a.r;
}
}sv[MAXN];
struct seg
{
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
int sum[MAXN<<2];
inline void push_up(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
sum[rt]=0;
if(l==r)
return ;
int mid=(l+r)>>1;
build(lson);
build(rson);
}
void update(int pos,int val,int l,int r,int rt)
{
if(l==r)
{
sum[rt]=val;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid)
update(pos,val,lson);
if(pos>mid)
update(pos,val,rson);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return sum[rt];
int ret=0;
int mid=(l+r)>>1;
if(L<=mid)
ret+=query(L,R,lson);
if(mid
B.K-th Number(hdu6231)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6231
二分答案,统计有多少个区间的第k大的值大于等于我们二分的答案,如果区间数大于m,就提高下界继续二分,否则降低上界。计数的时候可以采用双指针。
代码:
#include
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
int a[MAXN],HASH[MAXN],tot,n,k;
ll m;
vector sv;
int getid(int x)
{
int ret=lower_bound(HASH+1,HASH+1+tot,x)-HASH;
return ret;
}
bool judge(int mid)
{
ll ret=0;
sv.clear();
sv.push_back(0);
for(int i=1;i<=n;i++)
{
if(a[i]>=mid)
{
sv.push_back(i);
}
}
for(int i=0;i=m;
}
void solve()
{
tot=0;
scanf("%d%d%lld",&n,&k,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
HASH[++tot]=a[i];
}
sort(HASH+1,HASH+1+tot);
tot=unique(HASH+1,HASH+1+tot)-HASH-1;
for(int i=1;i<=n;i++)
{
a[i]=getid(a[i]);
}
int l=1,r=tot;
int ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(judge(mid))
{
l=mid+1;
ans=mid;
}
else
{
r=mid-1;
}
}
printf("%d\n",HASH[ans]);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
C.Confliction(hdu6232)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6232
将运动转换为B对于A的相对运动,然后答案就是经过次数最多的那个点,然后离散化时间和坐标,进行差分求解出现的次数最多的那个点就好了,不过挺难写的啊?
代码:
#include
using namespace std;
typedef long long ll;
const int MAXN=2e5+5;
int Na,Nb,Ac[MAXN],Bc[MAXN];
ll At[MAXN],Bt[MAXN],Hash[MAXN*2],sz;
vector > seg;
void solve()
{
ll pos=0;
seg.clear();
scanf("%d",&Na);
for(int i=1;i<=Na;i++)
{
scanf("%d%lld",&Ac[i],&At[i]);
if(At[i]==0) i--,Na--;
}
scanf("%d",&Nb);
for(int i=1;i<=Nb;i++)
{
scanf("%d%lld",&Bc[i],&Bt[i]);
if(Bt[i]==0) i--,Nb--;
}
sz=0;
for(int i=1;i<=Na;i++)
{
At[i]+=At[i-1];Hash[++sz]=At[i];
}
for(int i=1;i<=Nb;i++)
{
Bt[i]+=Bt[i-1];Hash[++sz]=Bt[i];
}
sort(Hash+1,Hash+1+sz);
sz=unique(Hash+1,Hash+1+sz)-Hash-1;
seg.push_back(make_tuple(0,3,1));
seg.push_back(make_tuple(1,3,-1));
for(int i=1,pa=1,pb=1;i<=sz;i++)
{
while(At[pa]r) swap(l,r);
int k=3;
if(delta==2||delta==-2) k=(l&1)?1:2;
seg.push_back(make_tuple(l,k,1));
seg.push_back(make_tuple(r+1,k,-1));
}
pos+=t*delta;
}
sort(seg.begin(),seg.end());
ll mx=0,cnt0=0,cnt1=0;
for(int i=0,j=0;i(seg[j])==get<0>(seg[i]))
{
if(get<1>(seg[j])&1) cnt1+=get<2>(seg[j]);
if(get<1>(seg[j])&2) cnt0+=get<2>(seg[j]);
j++;
}
if(get<0>(seg[i])&1) mx=max(mx,cnt1);
else mx=max(mx,cnt0);
}
printf("%lld\n",mx);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
D.X-Men(hdu6233)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6233
这可能是本场比赛第二简单的题目???现场榜被带歪了啊???其实理性分析一下,可以发现,每次最远的两个人的距离一定会减少2,所以直接直径除二向下取整数就好了。
代码:
#include
using namespace std;
const int MAXN=1005;
struct edge
{
int to,nxt;
}E[MAXN*2];
int head[MAXN],tot,root,mx;
bool book[MAXN];
void addedge(int u,int v)
{
E[tot].to=v;E[tot].nxt=head[u];head[u]=tot++;
E[tot].to=u;E[tot].nxt=head[v];head[v]=tot++;
}
void init(int n)
{
tot=0;
memset(book,0,sizeof(book));
for(int i=1;i<=n;i++)
{
head[i]=-1;
}
}
void dfs(int now,int fa,int dp)
{
if(book[now]&&dp>mx)
{
mx=dp;
root=now;
}
for(int i=head[now];~i;i=E[i].nxt)
{
int v=E[i].to;
if(v==fa)
continue;
dfs(v,now,dp+1);
}
}
void solve()
{
int n,m;
scanf("%d%d",&n,&m);
init(n);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
book[x]=true;
root=x;
}
for(int i=1;i
F.Permutation(hdu6235)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6235
水题,随便构造一下就好。。。
代码:
#include
using namespace std;
const int MAXN=1e5+5;
int a[MAXN];
void solve()
{
int n;
scanf("%d",&n);
int cnt=1;
for(int i=1;i<=n;i+=2)
{
a[i]=cnt++;
}
for(int i=2;i<=n;i+=2)
{
a[i]=cnt++;
}
printf("%d",a[1]);
for(int i=2;i<=n;i++)
{
printf(" %d",a[i]);
}
printf("\n");
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
H.A Simple Stone Game(hdu6237)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6237
首先我们将数组a的所有值加起来得到sum,然后求sum的所有的素因子,然后直接枚举所有的素因子就好了,设我们当前的素因子为p,我们对a数组所有的值对p取模,然后按照从大到小排序,然后贪心的移动就好了(每次把最大的填到p),存素因子的数组不用long long wa的莫名其妙?
代码:
#include
using namespace std;
typedef long long ll;
const int MAXN=1e5+5;
int a[MAXN],b[MAXN];
ll pre[MAXN];
vector sv;
void Prime(ll x)
{
sv.clear();
for(ll i=2;i*i<=x;i++)
{
if(x%i==0) sv.push_back(i);
while(x%i==0) x/=i;
}
if(x!=1) sv.push_back(x);
}
void solve()
{
int n;
ll sum=0,ans=1e18;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
Prime(sum);
for(int i=0;i=1;j--)
{
if(tot==pre[j]) break;
tot+=p-b[j];
}
ans=min(ans,tot);
}
printf("%lld\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
J.Interview(hdu6239)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6239
我们队猜出了个线性的式子...可能正解要用到i^k (k<=3)的求和公式,不知道我们这个式子为啥是对的...可能最后化简出来就是我们的式子吧,具体看代码
代码:
#include
using namespace std;
typedef long long ll;
const int MOD=1e9+7;
ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)
{
ret*=a;
ret%=MOD;
}
a=(a*a)%MOD;
b>>=1;
}
return ret;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
int n,d;
scanf("%d%d",&n,&d);
if(d==1)
printf("%lld\n",(2LL*n+4LL)%MOD*qpow(8,MOD-2)%MOD);
else
printf("%lld\n",(3LL*n+6LL)%MOD*qpow(8,MOD-2)%MOD);
}
return 0;
}
K.Server(hdu6240)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6240
分数规划经典问题哦,感觉自己分数规划还是掌握的不太好啊,看了zzq神犇的博客重新回忆了一下,发现自己为啥在求最大值啊?首先肯定是要二分答案的,然后,就是转化为最小值是否大于0的问题,对于最小值的问题,可以直接进行dp,我们首先按照右端点进行排序,对于将所有花费变为a-mid*b,然后对于所有花费为负的线段,我们一定会选,所以我们首先把花费为负的线段花费变成0,然后进行dp,最后将所有的为负的花费的权值加入,即可得到最小花费,dp的过程要用线段树来维护。好像跑最短路也可以?
代码:
#include
using namespace std;
const int MAXN=1e5+5;
const double INF=1e9;
const double eps=1e-6;
int n,t;
struct monitor
{
int s,t,a,b;
double val;
bool operator < (const monitor &o)const
{
return t>1;
build(lson);
build(rson);
}
void update(int pos,double val,int l,int r,int rt)
{
if(l==r)
{
mi[rt]=min(val,mi[rt]);
return ;
}
int mid=(l+r)>>1;
if(mid>=pos)
update(pos,val,lson);
if(mid>1;
double ret=INF;
if(L<=mid)
ret=min(ret,query(L,R,lson));
if(mid0)
{
l=mid;
ans=mid;
}
else
{
r=mid;
}
}
printf("%.3lf\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
L.Color a Tree(hdu6241)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6241
二分答案,然后将子树外的问题转换成子树内最多有多少点的问题,然后从叶子开始合并区间,判断每个节点是否可行,最后还要判断二分的值是否在根的可行区间当中。
代码:
#include
using namespace std;
const int MAXN=1e5+5;
struct edge
{
int v,nxt;
}E[MAXN*2];
struct node
{
int up,down;
}tr[MAXN];
struct lim
{
int id,num;
}A[MAXN],B[MAXN];
int head[MAXN],sz[MAXN],tot,n,na,nb;
bool flag;
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v)
{
E[tot].v=v;E[tot].nxt=head[u];head[u]=tot++;
E[tot].v=u;E[tot].nxt=head[v];head[v]=tot++;
}
void getlim(int mid)
{
for(int i=1;i<=n;i++)
{
tr[i].down=0,tr[i].up=sz[i];
}
for(int i=1;i<=na;i++)
{
int id=A[i].id,num=A[i].num;
tr[id].down=max(tr[id].down,num);
}
for(int i=1;i<=nb;i++)
{
int id=B[i].id,num=B[i].num;
tr[id].up=min(tr[id].up,mid-num);
}
for(int i=1;i<=n&&flag;i++)
{
if(tr[i].down>tr[i].up)
flag=false;
}
}
void dfssz(int now,int fa)
{
sz[now]=1;
for(int i=head[now];~i;i=E[i].nxt)
{
int v=E[i].v;
if(v==fa)
continue;
dfssz(v,now);
sz[now]+=sz[v];
}
}
void dfslim(int now,int fa)
{
int down=0,up=0;
for(int i=head[now];(~i)&&flag;i=E[i].nxt)
{
int v=E[i].v;
if(v==fa)
continue;
dfslim(v,now);
down+=tr[v].down,up+=tr[v].up;
}
tr[now].down=max(tr[now].down,down);
tr[now].up=min(tr[now].up,up+1);
//printf("%d:%d %d\n",now,tr[now].down,tr[now].up);
if(tr[now].down>tr[now].up)
flag=false;
}
void judge(int mid)
{
getlim(mid);
dfslim(1,0);
if(!(tr[1].down<=mid&&mid<=tr[1].up))
flag=false;
}
void solve()
{
init();
scanf("%d",&n);
for(int i=1;i>1;
judge(mid);
if(flag)
{
r=mid-1;
ans=mid;
}
else
{
l=mid+1;
}
}
printf("%d\n",ans);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
M.Geometry Problem(hdu6242)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6242
理性分析一下,就会发现,随机三个点然后求圆心即可,期望是8次就能随中。
代码:
#include
using namespace std;
const int MAXN=1e5+5;
const double eps=1e-6;
int sgn(double x)
{
if(fabs(x)=2&&n<=4)
{
gettwo(P[1],P[2]);
return ;
}
while(1)
{
memset(id,0,sizeof(id));
getid();
if(!judge(P[id[0]],P[id[1]],P[id[2]]))
continue;
Circle res=CircumCircle(Traingle(P[id[0]],P[id[1]],P[id[2]]));
int cnt=0;
for(int i=1;i<=n;i++)
{
double dis=Dis(P[i],res.center);
if(sgn(dis-res.r)==0)
cnt++;
}
if(cnt>=(n+1)/2)
{
printf("%lf %lf %lf\n",res.center.x,res.center.y,res.r);
return ;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
srand(0);
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}