题目好像没有放出来,自己去网上找吧
T1:
这题就是个裸贪心,直接记录每个点最多的收益以及是否唯一,然后更新的话,就把儿子收益排序,如果选到的儿子中有不唯一的,或者最后几个可以换的,或者有收益为0可选可不选的,就都不唯一
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100011;
int tot=0,now[maxn],son[maxn<<1],pre[maxn<<1];
void add(int a,int b){pre[++tot]=now[a]; now[a]=tot; son[tot]=b;}
void cc(int a,int b){add(a,b); add(b,a);}
int n,w[maxn],lim[maxn];
void init(){
scanf("%d",&n); w[1]=0; lim[1]=n+2; int a,b;
for (int i=2;i<=n;++i) scanf("%d",w+i);
for (int i=2;i<=n;++i) scanf("%d",lim+i),--lim[i];
for (int i=2;i<=n;++i) scanf("%d%d",&a,&b),cc(a,b);
}
struct Tp{
int f; bool ok;
Tp(){}
Tp(int f_,bool ok_):f(f_),ok(ok_){}
};
inline bool cmp_Tp_f(Tp a,Tp b){return a.f>b.f;}
int f[maxn]; bool ok[maxn];
void TreeDp(int x,int fa=0){
for (int p=now[x];p;p=pre[p]) if (son[p]!=fa) TreeDp(son[p],x);
static Tp a[maxn]; int sum=0;
for (int p=now[x];p;p=pre[p]) if (son[p]!=fa) a[++sum]=Tp(f[son[p]],ok[son[p]]);
sort(a+1,a+sum+1,cmp_Tp_f);
f[x]=w[x]; int k=0; while (k<min(lim[x],sum) && a[k+1].f>0) f[x]+=a[++k].f;
ok[x]=0; for (int i=1;i<=k;++i) ok[x]|=a[i].ok;
if (k<sum && (!a[k+1].f || a[k+1].f==a[k].f)) ok[x]=1;
}
void work(){
TreeDp(1); printf("%d\n",f[1]);
puts(ok[1]?"solution is not unique":"solution is unique");
}
int main(){
freopen("salesman.in","r",stdin); freopen("salesman.out","w",stdout);
init(); work();
fclose(stdin); fclose(stdout);
return 0;
}
T2:
就是一道蘑菇题(就是那种难不死你也要烦死你的题),拿180对称举例,先把原数组a按180转一下得到b,然后判断一个矩阵x,y是否是180的话,就找到他转了后对应的坐标x1,y1,只要判断a[x][y]是否等于b[x1][y1]就行了(这里的x,y不是指一个点,而是整个矩阵的x,y ,也可以理解为每个点的x,y),于是要建7个矩阵,各种坐标转化,还要hash判断,这样是O(n^3)的,不要想过,毕竟7个,于是发现其实答案是有单调性的,但是奇偶要分开考虑,于是变成O(n^2logn),但是还是被卡常,改了好久最好把hash改成自然溢出才过了。。。(这题让我认识到了template的重要性)
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
#define CK(x) check_##x
#define CHK(x,len,i,j) check_##x(len,i,j)
using namespace std;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxn=511,d1=233,d2=2333;
uint h[maxn][maxn],h0[maxn][maxn],h1[maxn][maxn],
h2[maxn][maxn],h3[maxn][maxn],h4[maxn][maxn],h5[maxn][maxn];
uint Ppow[maxn],Qpow[maxn]; int n;
void init(){
scanf("%d",&n); static char s[maxn];
for (int i=1;i<=n;++i){
scanf("%s",s+1);
for (int j=1;j<=n;++j) h[i][j]=s[j]-'0';
}
Ppow[0]=1; for (int i=1;i<=n;++i) Ppow[i]=Ppow[i-1]*d1;
Qpow[0]=1; for (int i=1;i<=n;++i) Qpow[i]=Qpow[i-1]*d2;
}
/*
0代表竖对称,1代表横对称,2代表主对角线对称,3代表副对角线对称
4代表顺时针90度转,5代表180度转
*/
void buildh(){
for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) if (h[i][j])
h0[i][n-j+1]=h1[n-i+1][j]=h2[j][i]=h3[n-j+1][n-i+1]=
h4[j][n-i+1]=h5[n-i+1][n-j+1]=1;
}
void get(uint a[][maxn]){
for (int i=1;i<=n;++i){
int P=Ppow[n-i];
for (int j=1;j<=n;++j){
a[i][j]=a[i][j]*P*Qpow[n-j];
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
}
}
}
void gethash(){
get(h),get(h0),get(h1),get(h2),get(h3),get(h4),get(h5);
}
inline uint gao(uint h[][maxn],int len,int x,int y){
return (h[x][y]-h[x-len][y]-h[x][y-len]+h[x-len][y-len])
*Ppow[x]*Qpow[y];
}
inline bool check_0(const int &len,const int &x,const int &y){
uint tmp=gao(h,len,x,y);
return tmp==gao(h0,len,x,n-y+len) || tmp==gao(h1,len,n-x+len,y)
|| tmp==gao(h2,len,y,x) || tmp==gao(h3,len,n-y+len,n-x+len);
}
inline bool check_90(int &len,int &x,int &y){
return gao(h,len,x,y)==gao(h4,len,y,n-x+len);
}
inline bool check_180(int &len,int &x,int &y){
return gao(h,len,x,y)==gao(h5,len,n-x+len,n-y+len);
}
inline bool check_4(int &len,int &x,int &y){
return CHK(180,len,x,y) && CHK(0,len,x,y);
}
inline bool check_8(int &len,int &x,int &y){
return CHK(90,len,x,y) && CHK(0,len,x,y);
}
template <class T> bool check(int len,T f){
for (int i=len;i<=n;++i)
for (int j=len;j<=n;++j) if (f(len,i,j)) return true;
return false;
}
template <class T> int calc(T f){
int l,r,mid;
for (l=1,r=n/2;mid=(l+r)/2,l<=r;)
if (check(2*mid,f)) l=mid+1;else r=mid-1;
--l; if (!check(2*l+1,f)) return 2*l;
for (r=n/2;mid=(l+r)/2,l<=r;)
if (check(2*mid+1,f)) l=mid+1;else r=mid-1;
--l; return 2*l+1;
}
void solve(){
printf("%d %d ",calc(CK(8)),calc(CK(90)));
printf("%d %d ",calc(CK(4)),calc(CK(180)));
printf("%d\n",calc(CK(0)));
}
void work(){
buildh(); gethash(); solve();
}
int main(){
freopen("symmetry.in","r",stdin); freopen("symmetry.out","w",stdout);
init(); work();
fclose(stdin); fclose(stdout);
return 0;
}
T3:
这就是判断无根树同构,就是先找到重心(有两个的话就在两点间加一个新点作为重心),然后转化为有根树同构,记录每个点子树的hash值即可,树同构HK hash会被卡的毛都不剩(这题数据好像没有卡),由于记不住hash的正确姿势,就随便搞了一堆很复杂的东西,于是就Ok了。 顺便补一下正确的hash,先把儿子hash从小到大排序,然后每次H=(H*a^hash[son]+b)%c,H初值为1,a,b,c是常数,hash[x]=H; 这好像是有证明非常难卡的,以后要记住了。。。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxm=22,maxn=10011,Index=30077,mod=1000000009,Idx2=23333,md2=1000000007;
int m;
void init(){
scanf("%d",&m);
}
int tot,now[maxn],pre[maxn<<1],son[maxn<<1],rd[maxn];
void add(int a,int b){pre[++tot]=now[a]; now[a]=tot; son[tot]=b; ++rd[b];}
struct Tp{
int h1,h2;
Tp(){}
Tp(int h1_,int h2_):h1(h1_),h2(h2_){}
};
int hash1[maxn],hash2[maxn];
inline bool cmp_Tp_h1(Tp a,Tp b){return (a.h1>b.h1) || (a.h1==b.h1 && a.h2<b.h2);}
void gethash(int x,int fa){
if (!x) return;
if (rd[x]==2 && fa){
for (int p=now[x];p;p=pre[p]) if (son[p]!=fa && son[p]) gethash(son[p],x);
for (int p=now[x];p;p=pre[p]) if (son[p]!=fa && son[p])
hash1[x]=hash1[son[p]],hash2[x]=hash2[son[p]];
return;
}
for (int p=now[x];p;p=pre[p]) if (son[p]!=fa && son[p]) gethash(son[p],x);
static Tp a[maxn]; int sum=0;
for (int p=now[x];p;p=pre[p]) if (son[p]!=fa && son[p])
a[++sum]=Tp(hash1[son[p]],hash2[son[p]]);
if (!sum){hash1[x]=hash2[x]=1; return;}
sort(a+1,a+sum+1,cmp_Tp_h1); int r1=233,r2=2333;
for (int i=1;i<=sum;++i) r1=(1LL*r1*Index+a[i].h1)%mod,
r2=(1LL*r2*Idx2+1LL*a[i].h2*a[i].h2+1LL*rd[x]*a[i].h2+a[i].h1)%md2;
hash1[x]=r1; hash2[x]=r2;
}
int n;
int find_root(){
static int sz[maxn],q[maxn],fa[maxn]; int w=1; q[1]=1; fa[1]=0;
memset(sz,0,sizeof(sz)); sz[1]=1;
for (int i=1;i<=w;++i) for (int p=now[q[i]];p;p=pre[p])
if (!sz[son[p]]) q[++w]=son[p],sz[q[w]]=1,fa[q[w]]=q[i];
for (int i=1;i<=n;++i) if (rd[i]==2) sz[i]=0;
for (int i=w;i>=1;--i) sz[fa[q[i]]]+=sz[q[i]];
int a=-1; for (int i=n;i>=1;--i) if (sz[q[i]]*2>=sz[1]){a=q[i]; break;}
if (sz[a]!=sz[1]/2) return a;
int b=a; while (sz[fa[b]]==sz[1]/2) b=fa[b]; ++n;
add(a,n); add(n,a); add(fa[b],n); add(n,fa[b]);
for (int p=now[a];p;p=pre[p]) if (son[p]==fa[a]) son[p]=0;
for (int p=now[fa[b]];p;p=pre[p]) if (son[p]==b) son[p]=0; return n;
}
void solve(int &h1,int &h2,int &s){
scanf("%d",&n); int a,b; s=0;
memset(rd,0,sizeof(rd)); tot=0; memset(now,0,sizeof(now));
for (int i=1;i<n;++i) scanf("%d%d",&a,&b),add(a,b),add(b,a);
for (int i=1;i<=n;++i) if (rd[i]!=2) ++s;
int x=find_root(); gethash(x,0); h1=hash1[x]; h2=hash2[x];
}
void work(){
static int hash1[maxm],hash2[maxm],s[maxm];
for (int i=1;i<=m;++i) solve(hash1[i],hash2[i],s[i]);
static bool ok[maxm];
for (int i=1;i<=m;++i) for (int j=i+1;j<=m;++j){
if (hash1[i]==hash1[j] && hash2[i]==hash2[j] && s[i]==s[j]) {ok[i]=1; break;}
}
static int a[maxm]; int sum=0;
for (int i=1;i<=m;++i) if (!ok[i]) a[++sum]=s[i];
sort(a+1,a+sum+1); cout<<sum<<endl;
for (int i=1;i<=sum;++i) cout<<a[i]<<' '; puts("");
}
int main(){
freopen("isomorphism.in","r",stdin); freopen("isomorphism.out","w",stdout);
init(); work();
fclose(stdin); fclose(stdout);
return 0;
}