JSOI2015day1

来源:互联网 发布:工业设计软件s 编辑:程序博客网 时间:2024/06/06 00:16

题目好像没有放出来,自己去网上找吧

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;}


0 0