A A Simple Problem with Integers (HDU 4267)
树状树组维护arr[i]-arr[i-1],实现成段更新单点查询。
#include<cstdio>
#include<cstring>
const int N=55555;
struct TreeArr
{
int arr[N],n;
void init(int n){memset(arr,0,4*n+4);this->n=n;}
void update(int k,int v){while(k<=n) arr[k]+=v,k+=k&-k;}
void update(int a,int b,int v){update(a,v);update(b+1,-v);}
int query(int k){int ans=0;while(k) ans+=arr[k],k-=k&-k;return ans;}
}ta[12][12];
int val[N];
int main()
{
int n,q;freopen("in.txt","r",stdin);
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++) for(int j=0;j<i;j++) ta[i][j].init(n);
for(int i=1;i<=n;i++) scanf("%d",val+i);
scanf("%d",&q);
int op,a,b,k,c;
while(q--)
{
scanf("%d%d",&op,&a);
if(op==1) scanf("%d%d%d",&b,&k,&c),ta[k][a%k].update(a,b,c);
else
{
int ans=val[a];
for(int i=1;i<=n;i++) ans+=ta[i][a%i].query(a);
printf("%d\n",ans);
}
}
}
return 0;
}
B Alice and Bob (HDU 4268)
贪心,每次从剩余的所有不大于a.x的数中选择一个不大于a.y且y最大的删去
#include<set>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef pair<int,int>tp;
const int N=100010;
tp a[N],b[N];
int main()
{
int t;//freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t--)
{
int x,y,n,ans=0;
multiset<int>s;
multiset<int>::iterator it;
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d%d",&a[i].first,&a[i].second);
for(int i=0;i<n;i++) scanf("%d%d",&b[i].first,&b[i].second);
sort(a,a+n);
sort(b,b+n);
for(int i=0,j=0;i<n;i++)
{
while(j<n&&b[j]<=a[i]) s.insert(b[j++].second);
it=s.upper_bound(a[i].second);
if(it!=s.begin()) ans++,s.erase(--it);
}
printf("%d\n",ans);
}
return 0;
}
C Defend Jian Ge (HDU 4269)
不过我测过了HDOJ数据里
没有将消耗型装备作为合成装备的材料的数据存在
#include<map>
#include<vector>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<string,int> tp;
#define pb push_back
struct Nod
{
string s,ss[6];
int val,cnt,c[6],kind,totval;
Nod(){cnt=0;}
Nod(string s,int v,int kind):s(s),val(v),kind(kind){cnt=0;}
};
map<string,int>si;
vector<Nod>eq;
int cal(int i)
{
int ans=eq[i].val;
for(int j=0;j<eq[i].cnt;j++) ans+=cal(si[eq[i].ss[j]])*eq[i].c[j];
return ans;
}
int main()
{
int n1,n2,n3,m,val,tmp,cas=1;
while(cin>>n1)
{
string s;si.clear();eq.clear();
for(int i=0;i<n1;i++) cin>>s>>val,eq.pb(Nod(s,val,1));
cin>>n2;cin.ignore();
for(int i=0;i<n2;i++)
{
getline(cin,s);istringstream iss(s);
Nod tmp;iss>>tmp.s>>tmp.val;tmp.kind=2;
while(iss>>s>>tmp.ss[tmp.cnt]>>tmp.c[tmp.cnt]) tmp.cnt++;
eq.pb(tmp);
}
cin>>n3;
for(int i=0;i<n3;i++) cin>>s>>val,eq.pb(Nod(s,val,3));
for(int i=0;i<eq.size();i++) si[eq[i].s]=i;
for(int i=0;i<eq.size();i++) eq[i].totval=cal(i);
vector<tp>bag,bag2;
vector<tp>::iterator it;
#define myfind(a,s) for(it=a.begin();it!=a.end()&&it->first!=s;it++)
int gold=0;cin>>m;
while(m--)
{
cin>>s;
if(s[0]=='+')
{
s.erase(0,1);
if(si.find(s)==si.end())
{
int tmp=0;
for(int i=0;s[i];i++) tmp=tmp*10+s[i]-48;
gold+=tmp;
}
else
{
int i=si[s],fg=1;
if(gold<eq[i].val) continue;
if(eq[i].kind!=3)
{
bag2=bag;
for(int j=0;j<eq[i].cnt;j++) for(int k=0;k<eq[i].c[j];k++)
{
myfind(bag2,eq[i].ss[j]);
if(it==bag2.end()) fg=0;
else bag2.erase(it);
}
bag2.pb(tp(s,1));
if(!fg||bag2.size()>6) continue;
bag=bag2;gold-=eq[i].val;
}
else
{
if(bag.size()==6) continue;
myfind(bag,s);
if(it==bag.end()) bag.pb(tp(s,1));
else it->second++;
gold-=eq[i].val;
}
}
}
else
{
s.erase(0,1);myfind(bag,s);
if(it==bag.end()) continue;
gold+=eq[si[s]].totval*it->second;
bag.erase(it);
}
}
cout<<"Case "<<cas++<<":"<<endl<<gold<<endl<<bag.size()<<endl;
sort(bag.begin(),bag.end());
for(int i=0;i<bag.size();i++) cout<<bag[i].first<<": "<<bag[i].second<<endl;
cout<<endl;
}
return 0;
}
D Dynamic Lover (HDU 4270)
犹豫了好多几天,看过了后缀自动机的算法但自己就是写不来,最终还是决定把标程收为模板用吧。
#include<cstdio>
#include<cstring>
const int N=200020;
struct Nod
{
int fail,nxt[27],deep;
int s,pos;
void clear()
{
memset(nxt,0,sizeof(nxt));
deep=fail=s=0;
}
}node[N*2];
int size,end;
bool dlt[N*2];
int id[N];
int tot,len;
void init()
{
memset(dlt,0,sizeof(dlt));
for(int i=0;i<27;i++) node[0].nxt[i]=1;
node[0].deep=-1;
node[1].clear();
tot=len=end=1;size=2;id[0]=1;
}
bool isDlt(int x)
{
return x==0||dlt[node[x].s];
}
void addNode(int c,int s)
{
int p=size++;node[p].clear();
node[p].s=s;id[len]=p;
node[p].deep=node[end].deep+1;
node[p].pos=len++;
for(;isDlt(node[end].nxt[c]);end=node[end].fail) node[end].nxt[c]=p;
int p1=node[end].nxt[c];
if(node[p1].deep==node[end].deep+1) node[p].fail=p1;
else
{
int p2=size++;node[p2]=node[p1];node[p1].fail=node[p].fail=p2;
node[p2].deep=node[end].deep+1;
for(;node[end].nxt[c]==p1;end=node[end].fail) node[end].nxt[c]=p2;
}
end=p;
}
void addString(char *s)
{
for(int i=0;s[i];i++) addNode(s[i]-96,tot++);
}
void dltString(int k)
{
for(int i=1;i<=k;i++) dlt[node[id[len-i]].s]=1;
end=id[len-1-k];len-=k;
}
bool first;
int dfs(int x,int &l)
{
if(l==0) return node[x].pos;
for(int i=0;i<27;i++)
{
if(i==0&&first){first=0;continue;}
if(isDlt(node[x].nxt[i])) continue;
l--;
return dfs(node[x].nxt[i],l);
}
return node[x].pos;
}
int query(int l)
{
first=1;
addNode(0,tot++);
int tl=l;
int id=dfs(1,tl);
dltString(1);
l-=tl;
return id-l+1;
}
char s[N];
int main()
{
while(scanf("%s",s)!=EOF)
{
init();
addString(s);
int n,x,l;
scanf("%d",&n);
while(n--)
{
scanf("%d",&x);
switch(x)
{
case 1:scanf("%s",s);addString(s);break;
case 2:scanf("%d",&l);printf("%d\n",query(l));break;
case 3:scanf("%d",&l);dltString(l);break;
}
}
}
return 0;
}
E Find Black Hand (HDU 4271)
DP什么的最坑最烦了
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int,string>tp;
#define _min(a,b,c) min(a,min(b,c))
int n,dp[111111][11];
char s[111111],ss[11][11];
tp a[11];
int cal(char *a,char *b,int la,int lb)
{
int ans=1e8;
for(int i=0;i<=lb;i++) dp[0][i]=i;
for(int i=0;i<la;i++)
{
for(int j=0;j<lb;j++)
dp[i+1][j+1]=_min(dp[i][j]+(a[i]!=b[j]),dp[i+1][j]+1,dp[i][j+1]+1);
ans=min(ans,dp[i+1][lb]);
}
return ans;
}
void solve()
{
int len=strlen(s),lim=min(len,20);
for(int i=0;i<lim;i++) s[len+i]=s[i];s[len+lim]=0;
if(len<20)
{
for(int i=0;i<n;i++)
{
int tmp=1e8;
for(int j=0;j<len;j++) tmp=min(tmp,cal(s+j,ss[i],len,strlen(ss[i])));
a[i]=tp(tmp,ss[i]);
}
}
else
{
for(int i=0;i<n;i++) a[i]=tp(cal(s,ss[i],len+20,strlen(ss[i])),ss[i]);
}
}
int main()
{
while(scanf("%s%d",s,&n)!=EOF)
{
for(int i=0;i<n;i++) scanf("%s",ss[i]);
solve();sort(a,a+n);
printf("%s %d\n",a[0].second.c_str(),a[0].first);
}
return 0;
}
F LianLianKan (HDU 4272)
状态压缩DP。对于当前的i位置的元素,最多与a[i+9]位置的消去。a[i+1]、a[i+2]、a[i+3]、a[i+4]分别与a[i-4]、a[i-3]、a[i-2]、a[i-1]对应,则a[i]可能与a[i+5]、a[i+6]、a[i+7]、a[i+8]、a[i+9]对应。状态st用2进制10位表示i到i+9的10位是否被选
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1111;
int n,a[N],dp[N][N];
//0:未被选 1:已被选
int dfs(int i,int st)
{
if(i==n) return st==0;
if(~dp[i][n]) return dp[i][n];
if(st&1) return dp[i][n]=dfs(i+1,st>>1);
for(int j=1;j<=9&&i+j<n;j++)
if(((1<<j)&st)==0&&a[i]==a[i+j])
if(dfs(i+1,st>>1|(1<<j-1))) return dp[i][st]=1;
return dp[i][st]=0;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=n-1;~i;--i) scanf("%d",a+i);
memset(dp,255,sizeof(dp));
printf("%d\n",dfs(0,0));
}
return 0;
}
G Rescue (HDU 4273)
三维凸包模板题,代码无限长
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps=1e-8;
const int maxv=305;
typedef double db;
struct pt
{
db x,y,z;
pt(){}
pt(db x,db y,db z):x(x),y(y),z(z){}
pt operator - (const pt p){return pt(x-p.x,y-p.y,z-p.z);}
pt operator + (const pt p){return pt(x+p.x,y+p.y,z+p.z);}
pt operator * (pt p){return pt(y*p.z-z*p.y,z*p.x-x*p.z,x*p.y-y*p.x);}
pt operator / (double k){return pt(x/k,y/k,z/k);}
pt operator * (double k){return pt(x*k,y*k,z*k);}
double operator ^ (pt p){return (x*p.x+y*p.y+z*p.z);}
};
struct _3DCH
{
struct fac{int a,b,c;bool ok;};
int n,cnt,to[maxv][maxv];
pt P[maxv];
fac F[maxv*8];
double vlen(pt a){return sqrt(a.x*a.x+a.y*a.y+a.z*a.z);}
double volume(pt a,pt b,pt c,pt d){return (b-a)*(c-a)^(d-a);}
double ptof(pt &p,fac &f)
{
pt m=P[f.b]-P[f.a],n=P[f.c]-P[f.a],t=p-P[f.a];
return (m*n)^t;
}
void deal(int p,int a,int b)
{
int f=to[a][b];
fac add;
if(F[f].ok)
{
if(ptof(P[p],F[f])>eps) dfs(p,f);
else
{
add.a=b,add.b=a,add.c=p,add.ok=1;
to[p][b]=to[a][p]=to[b][a]=cnt;
F[cnt++]=add;
}
}
}
void dfs(int p,int cur)
{
F[cur].ok=0;
deal(p,F[cur].b,F[cur].a);
deal(p,F[cur].c,F[cur].b);
deal(p,F[cur].a,F[cur].c);
}
bool same(int s,int t)
{
pt &a=P[F[s].a],&b=P[F[s].b],&c=P[F[s].c];
return fabs(volume(a,b,c,P[F[t].a]))<eps&&fabs(volume(a,b,c,P[F[t].b]))<eps&&fabs(volume(a,b,c,P[F[t].c]))<eps;
}
void construct()
{
cnt=0;
if(n<4) return;
bool sb=1;
for(int i=1;i<n;i++) if(vlen(P[0]-P[i])>eps)
{
swap(P[1],P[i]);
sb=0;break;
}
if(sb) return;
sb=1;
for(int i=3;i<n;i++) if(fabs((P[0]-P[1])*(P[1]-P[2])^(P[0]-P[i]))>eps)
{
swap(P[3],P[i]);sb=0;break;
}
if(sb) return;
fac add;
for(int i=0;i<4;i++)
{
add.a=(i+1)%4,add.b=(i+2)%4,add.c=(i+3)%4,add.ok=1;
if(ptof(P[i],add)>0) swap(add.b,add.c);
to[add.a][add.b]=to[add.b][add.c]=to[add.c][add.a]=cnt;
F[cnt++]=add;
}
for(int i=4;i<n;i++) for(int j=0;j<cnt;j++) if(F[j].ok&&ptof(P[i],F[j])>eps)
{
dfs(i,j);break;
}
int tmp=cnt;cnt=0;
for(int i=0;i<tmp;i++) if(F[i].ok) F[cnt++]=F[i];
}
pt center()
{
pt ans(0,0,0),o(0,0,0);
double tot=0;
for(int i=0;i<cnt;i++)
{
double vol=volume(o,P[F[i].a],P[F[i].b],P[F[i].c]);
ans=ans+(o+P[F[i].a]+P[F[i].b]+P[F[i].c])/4*vol;
tot+=vol;
}
return ans/tot;
}
double dis(pt p,int i)
{
double vol=volume(P[F[i].a],P[F[i].b],P[F[i].c],p);
double s=vlen((P[F[i].b]-P[F[i].a])*(P[F[i].c]-P[F[i].a]));
return fabs(vol/s);
}
}hull;
int main()
{
while(scanf("%d",&hull.n)!=EOF)
{
for(int i=0;i<hull.n;i++) scanf("%lf%lf%lf",&hull.P[i].x,&hull.P[i].y,&hull.P[i].z);
hull.construct();
pt p=hull.center();
double ans=1e10;
for(int i=0;i<hull.cnt;i++) ans=min(ans,hull.dis(p,i));
printf("%.3f\n",ans);
}
return 0;
}
H Spy’s Work (HDU 4274)
每个结点初始化为[1,inf],dfs更新每个结点的[low,up],如果某个结点low>up即为lie,否则为true
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=22222;
int head[N],nxt[N],ev[N],e;
int low[N],up[N],fg;
void dfs(int u,int p)
{
int lim=1;
for(int i=head[u];~i;i=nxt[i])
{
if(ev[i]==p) continue;
dfs(ev[i],u);
lim+=low[ev[i]];
}
if(low[u]<lim) low[u]=lim;
if(low[u]>up[u]) fg=0;
}
int main()
{
int n,m,x,y;
while(scanf("%d",&n)!=EOF)
{
e=0;
for(int i=1;i<=n;i++) head[i]=-1,low[i]=1,up[i]=0x3f3f3f3f;
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
ev[e]=x,nxt[e]=head[i],head[i]=e++;
ev[e]=i,nxt[e]=head[x],head[x]=e++;
}
char op[2];fg=1;
for(scanf("%d",&m);m;m--)
{
scanf("%d%s%d",&x,op,&y);
if(op[0]=='<') up[x]=min(up[x],y-1);
if(op[0]=='>') low[x]=max(low[x],y+1);
if(op[0]=='=') low[x]=max(low[x],y),up[x]=min(up[x],y);
}
if(fg) dfs(1,1);
puts(fg?"True":"Lie");
}
return 0;
}
I Color the Tree (HDU 4275)
组合数学+树的同构(HASH)
- 先找树的重心,若存在两个重心,则分别以两个重心为根,拆成两个子树,最后合并计算。
- 对一个以u为根的子树,将u的所有儿子v1,v2,……,vn按hash[v1],hash[v2],……,hash[vn]的值分组(值相同的认为是同构的树),每一种情况都是有n个相同子树,每个子树有m种染色方案,求子树染色的不同情况为,此模型等价于将n个相同的球放入m个盒子的情况数。
- n个相同的球放入m个盒子又等价于:n+m-1的空位中选择m-1个位子插板形成m个区间(盒子),其它位置放小球ans=C(n+m-1,m-1)。又因为m-1可能很大,计算时用ans=C(n+m-1,m-1)=C(n+m-1,n)来算,即对n个子树根结点计算的复杂度是O(n),每个结点O(1),总共O(n).
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>tp;
#define clr(a,x) memset(a,x,sizeof(a))
const int BASE=35127,MUL=913121;
const int N=111111,mod=1e9+7;
int n,m;
int head[N],nxt[N],ev[N],e;
int lev[N],deg[N],que[N];
bool vis[N];
ll hash[N],ans[N];
tp arr[N];
ll pow(ll a,int n)//快速幂
{
ll b;
for(b=1;n;a=a*a%mod,n/=2) if(n&1) b=b*a%mod;
return b;
}
ll com(ll n,int m)//组合数
{
ll x=1,y=1;
for(int i=1;i<=m;i++) x=x*(n-i+1)%mod,y=y*i%mod;
return x*pow(y,mod-2)%mod;
}
void findRoot(int &a,int &b)//求重心
{
if(n==1){a=0,b=-1;return;}
clr(vis,0);clr(deg,0);
int st=0,ed=-1;
for(int i=0;i<n;i++)
{
for(int j=head[i];~j;j=nxt[j]) deg[i]++;
if(deg[i]<=1) vis[que[++ed]=i]=1,lev[i]=0;
}
while(st<=ed)
{
int u=que[st++];
for(int i=head[u];~i;i=nxt[i])
{
int v=ev[i];
if(!vis[v]&&--deg[v]<=1) vis[que[++ed]=v]=1,lev[v]=lev[u]+1;
}
}
a=que[ed];
b=lev[a]==lev[que[ed-1]]?que[ed-1]:-1;
}
void dfs(int u,int p)//求每个子树hash值并算出每个子树的ans
{
for(int i=head[u];~i;i=nxt[i])
{
if(ev[i]==p) continue;
dfs(ev[i],u);
}
ans[u]=m;hash[u]=BASE;int cnt=0;
for(int i=head[u];~i;i=nxt[i])
{
if(ev[i]==p) continue;
arr[cnt++]=tp(hash[ev[i]],ans[ev[i]]);
}
sort(arr,arr+cnt);
for(int j,i=0;i<cnt;i=j)
{
for(j=i;j<cnt&&arr[i].first==arr[j].first;j++)
hash[u]=((hash[u]*MUL)^arr[j].first)%mod;
ans[u]=ans[u]*com(arr[i].second+j-i-1,j-i)%mod;
}
}
ll solve()
{
int a,b;
findRoot(a,b);
dfs(a,b);
if(b==-1) return ans[a];//只有一个重心
dfs(b,a);
return hash[b]==hash[a]?ans[a]*(ans[a]+1)%mod*pow(2,mod-2)%mod:ans[a]*ans[b]%mod;
//两个重心对应子树是否同构。
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(head,-1,sizeof(head));e=0;
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);--u,--v;
ev[e]=v,nxt[e]=head[u];head[u]=e++;
ev[e]=u,nxt[e]=head[v];head[v]=e++;
}
printf("%I64d\n",solve());
}
return 0;
}
J The Ghost Blows Light (HDU 4276)
树形DP 先dfs求出1与n的最近距离,并将路径上的边权值改为0并更新剩余可用时间t=t-dis,若t小于0,则无解。
然后就随便从最短路径上选一个点(一般就选1或n了)作为树的根进行dfs,dp[i][t]表示i节点花费时间不超过t能获得的最大价值。
因为存在w=0的边,所以dp[u][j]=max(dp[u][j],dp[u][j-w]+dp[v][0])一定要最先更新,否则当w=0更新dp[u][j]的值时用的dp[u][j-w]不是最初的dp[u][j-w]了。
#include<cstdio>
#include<cstring>
#define max(a,b) ((a)>(b)?(a):(b))
int n,t,dp[111][555],val[111];
int head[111],nxt[222],ev[222],ew[222],e;
int dis(int u,int p)
{
if(u==n) return 0;
for(int i=head[u];~i;i=nxt[i])
{
if(ev[i]==p) continue;
int tmp=dis(ev[i],u)+ew[i];
if(tmp<ew[i]) continue;
else ew[i]=0;return tmp;
}
return -1;
}
void dfs(int u,int p)
{
for(int i=0;i<=t;i++) dp[u][i]=val[u];
for(int i=head[u];~i;i=nxt[i])
{
int v=ev[i],w=ew[i]*2;
if(v==p) continue;
dfs(v,u);
for(int j=t;j>=w;j--)
for(int k=0;k<=j-w;k++)
dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-w-k]);
}
}
int main()
{
while(scanf("%d%d",&n,&t)!=EOF)
{
memset(head,255,sizeof(head));e=0;
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
ev[e]=v,ew[e]=w,nxt[e]=head[u];head[u]=e++;
ev[e]=u,ew[e]=w,nxt[e]=head[v];head[v]=e++;
}
for(int i=1;i<=n;i++) scanf("%d",val+i);
t-=dis(1,1);
if(t<0){puts("Human beings die in pursuit of wealth, and birds die in pursuit of food!");continue;}
dfs(1,1);
printf("%d\n",dp[1][t]);
}
return 0;
}
K USACO ORZ (HDU 4277)
dfs复杂度为3^n,插入set时剪枝。x>y与x<y的情况等价出现,所以可以只考虑x<=y<=z
#include<set>
#include<iostream>
using namespace std;
long t,n,a[20],sum,x,y,z;
set<long>s;
void dfs(int i)
{
if(i==n)
{
if(x&&x<=y&&x<=z&&y<=z&&x+y>z) s.insert(x<<16|y);
return;
}
x+=a[i];dfs(i+1);x-=a[i];
y+=a[i];dfs(i+1);y-=a[i];
z+=a[i];dfs(i+1);z-=a[i];
}
int main()
{
for(cin>>t;t;t--)
{
cin>>n;sum=x=y=z=0;s.clear();
for(int i=0;i<n;i++) cin>>a[i],sum+=a[i];
dfs(0);
cout<<s.size()<<endl;
}
return 0;
}