T1
太鼓达人...我会说我考试的时候想了半天打表吗?当然不会
开大栈记得要点上执行命令...
#include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> #include <algorithm> #define ll long long #define rint register int #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; int n,len,maxp; int zhan[(1<<20)+1000],he; bool flag[(1<<20)+1000]; void dfs(int order,int now) { //printf("order=%d now=%d ",order,now); if(order==len+1) { if(!now) { for(int i=1;i<=len;++i) printf("%d",zhan[i]); printf(" "); exit(0); } return ; } if(flag[now]) return ; flag[now]=1; int tt; tt=(((now<<1)&maxp)|1); zhan[++he]=1; dfs(order+1,tt); --he; tt=((now<<1)&maxp); zhan[++he]=0; dfs(order+1,tt); --he; flag[now]=0; } int main(){ //freopen("T1biao.out","w",stdout); scanf("%d",&n); len=(1<<n); maxp=(1<<n)-1; dfs(1,0); }
迭代code (你现在应该知道我有多懒了...)
T2
树规...
状态数组:
$f_{i,j} 以第i个结点为根的子树走了j个点又回到i的最小花费$
$g_{i,j} 以第i个结点为根的子树走了j个点在任意点停下的最小花费$
然后进行背包就行了,记得枚举已有子树大小和当前加入子树大小,不要在外面枚举总的大小
#pragma GCC optimize("O3") #include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> #include <algorithm> #define ll long long #define rint register int #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } const int N=10006; int first[N*2],nt[N*2],w[N*2],ver[N*2],e; void addbian(int u,int v,int _w) { w[e]=_w; ver[e]=v; nt[e]=first[u]; first[u]=e++; } int n,K,root; int f[N][N];// 走回来 int g[N][N];// 不走回来 int fa[N],size[N]; void dfs(int x) { size[x]=1; f[x][0]=f[x][1]=0; g[x][0]=g[x][1]=0; int i,j,k,t1,t2; for(i=first[x];i!=-1;i=nt[i]) { if(ver[i]==fa[x]) continue; fa[ver[i]]=x; dfs(ver[i]); for(j=(size[x]<K?size[x]:K);j;--j) for(k=0;k<=size[ver[i]];++k) { if(j+k>K) break; t1=f[x][j]+f[ver[i]][k]+w[i]*2; if(f[x][j+k]>t1) f[x][j+k]=t1; t1=g[x][j]+f[ver[i]][k]+w[i]*2; t2=f[x][j]+g[ver[i]][k]+w[i]; if(t1>t2) t1=t2; if(g[x][j+k]>t1) g[x][j+k]=t1; } size[x]+=size[ver[i]]; } } int main(){ //freopen("T2.in","r",stdin); //freopen("T2.out","w",stdout); rint i,j; mem(first,-1); read(n); read(K); read(root); int tin1,tin2,tin3; for(i=1;i<n;++i) { read(tin1); read(tin2); read(tin3); addbian(tin1,tin2,tin3); addbian(tin2,tin1,tin3); } mem(f,60); mem(g,60); dfs(root); cout<<g[root][K]; }
T3
因子个数相同,显然将阶乘分解质因数,然后暴搜
首先你需要一个map记忆化,在搜的时候边乘边除gcd,使它们互质
因为相同的约数是无用的,这样不仅可以减少map的结点,还会变快
然后剪枝
发现2、3、5的数量很多,所以可以预处理出来,每个数对的数量,再开一个map存下来
假设当前dfs的数对是 A,B 它们互质,那么2、3、5贡献的数对必须是 B,A 才会相等
所以正确
还有一个剪枝
大的素数只有一个,所以可以跳过,在最后枚举用组合数计算
但是我没用,因为记忆化搜索够快了
/* 我认为把因子个数是1的跳过,在最后处理并不会加快 因为记忆化搜索不会因为这个慢... */ #include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> #include <algorithm> #include <map> #define ll long long #define rint register int #define mem(a,b) memset(a,b,sizeof(a)) #define ull unsigned long long #define dd double using namespace std; inline void read(int &x) { x=0; char q=getchar(); while(q<'0'||q>'9') q=getchar(); while(q>='0'&&q<='9') x=x*10+q-'0',q=getchar(); } ll gcd(ll x,ll y){return y==0?x:gcd(y,x%y);} int intgcd(int x,int y){return y==0?x:gcd(y,x%y);} struct son { ll s1,s2; son(){} son(ll _s1,ll _s2) { s1=_s1; s2=_s2; } bool friend operator < (son a,son b) { if(a.s1==b.s1) return a.s2<b.s2; return a.s1<b.s1; } }; int n; int num[28]; int prime[106],cnt,top; bool he[106]; map<son,ll> mp[26]; map<son,int> mm; void dfs1(int order,int A,int B) { int gg=intgcd(A,B); A/=gg; B/=gg; if(order==top+1) { // 这里不能A大B小,不然会重复 ++mm[son(A,B)]; return ; } for(int i=0;i<=num[order];++i) dfs1(order+1,A*(i+1),B*(num[order]-i+1)); } void chu() { rint i,j; for(i=2;i<=n;++i) { if(!he[i]) prime[++cnt]=i; for(j=1;j<=cnt&&i*prime[j]<=n;++j) { he[i*prime[j]]=1; if(i%prime[j]==0) break; } } int tt; for(i=1;i<=n;++i) { tt=i; for(j=1;j<=cnt;++j) while(tt%prime[j]==0) { ++num[j]; tt/=prime[j]; } } top=min(3,cnt); dfs1(1,1,1); } ll dfs(int order,ll A,ll B) { ll gg=gcd(A,B); A/=gg; B/=gg; if(A>B) A^=B,B^=A,A^=B; // A大B小可以优化掉一半 son hh=(son){A,B}; if(order==top) { if(mm.count(hh)) return mm[hh]; return 0; } if(mp[order].count(hh)) return mp[order][hh]; ll as=0; for(int i=num[order];i>=0;--i) as+=dfs(order-1,A*(i+1),B*(num[order]-i+1)); mp[order][hh]=as; return as; } int main(){ rint i,j; read(n); if(n==1) { printf("1"); return 0; } chu(); printf("%lld",dfs(cnt,1,1)/2); }