2017 Multi-University Training Contest - Team 7
HDU6121 Build a tree
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6121
题目意思:一棵 n 个点的完全 k 叉树,结点标号从 0 到 n - 1,求以每一棵子树的大小的异或和。
思路:一层一层的算,附上我的灵魂画作
我们来模拟计算一下上面这个非完全k叉树所有子树的大小异或之和。
对于第四层对于以该层节点为根的子树的大小为1,我们发现这一层总共有12个这样的子树,所以ans+=0;
对于第三层对于以该层节点为根的子树的大小为4,也就是说每个点我们需要在第四层里面为他分配三个子节点,一共可以分配出四个大小为3的子树,所以ans+=3;
对于第二层对于以该层节点为根的子树的小为13,也就是说每个点我们需要在第四层里面为他分配9个作为他的子节点,一共可以分配出1个这样的大小为13的子树,这样第四层还余下三个节点,我们继续构造我们形成一颗大小为7(4+3)的节点,所以对于第二层我们一共得到了一个大小为13的子树,1个大小为7的子树,一个大小为4的子树。
对于第一层我们同样可以利用这个方法计算出。
我们可以发现我们需要计算某一层的的贡献的时候,我们需要以下几个数据:
1.以该层的点为根的子树到底部这么多层的满树有多少个节点,该满树的最后一层有多少个节点。
2.以该层的点为根的子树到底部这么多层减去一层的满树有多少个节点。
这样我们就可以计算最后一层的点的数量对于每一层节点为根的不同子树的大小的和数量,就可以方便的计算了。
最后还要注意1叉树的情况,答案就是1^………………^n,这个网络上有公式和代码。这里抄了一份。
代码:
1 //Author: xiaowuga 2 #include <iostream> 3 #include <algorithm> 4 #include <set> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 #include <cstring> 9 #include <cstdio> 10 #include <ctime> 11 #include <map> 12 #include <bitset> 13 #include <cctype> 14 #define maxx INT_MAX 15 #define minn INT_MIN 16 #define inf 0x3f3f3f3f 17 #define mem(s,ch) memset(s,ch,sizeof(s)) 18 #define nc cout<<"nc"<<endl 19 #define sp " " 20 const long long N=100000; 21 using namespace std; 22 typedef long long LL; 23 typedef int II; 24 LL n,k; 25 LL ta[64],tal[64],p; 26 LL ans=0; 27 void init(){ 28 ta[0]=0; 29 ta[1]=1; 30 tal[1]=1; 31 p=2; 32 while(1){ 33 tal[p]=tal[p-1]*k; 34 ta[p]=ta[p-1]+tal[p]; 35 if(ta[p]>=n) break; 36 p++; 37 } 38 tal[p]=n-ta[p-1]; 39 ta[p]=n; 40 } 41 LL xor_n(LL n){ 42 43 LL t = n & 3; 44 45 if (t & 1) return t / 2LL ^ 1; 46 47 return t / 2LL ^ n; 48 49 } 50 void solve(){ 51 for(LL lay=p-1;lay>=1;lay--){ 52 LL num=n-ta[lay-1]; 53 LL a=ta[p-lay]; 54 LL b=tal[p-lay+1]; 55 num-=tal[lay]*a; 56 LL c=num/b,d=num%b; 57 if(c%2){ 58 ans^=ta[p-lay+1]; 59 } 60 if(d!=0){ 61 ans^=(a+d); 62 } 63 LL e=tal[lay]; 64 e-=c; 65 if(d!=0) e--; 66 if(e%2&&e>0){ 67 ans^=a; 68 } 69 } 70 } 71 int main() { 72 ios::sync_with_stdio(false);cin.tie(0); 73 II T; 74 cin>>T; 75 while(T--){ 76 cin>>n>>k; 77 if(k==1){ cout<<xor_n(n)<<endl;continue;} 78 k=min(k,n-1); 79 init(); 80 ans=0; 81 if(tal[p]%2) ans^=1; 82 solve(); 83 cout<<ans<<endl; 84 } 85 }
HDU6124 Euler theorem
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6124
题目意思:给出一个a,对于任意的b,得到c=a%b,求c的种类。
数据结构:很明显0和a本身都是一个答案,很自然我们想到答案肯定还有1,2,3,4,5,…………(a-1)/2, 因为(a-1)/2是最后一个乘以2不超过a的值。所以公式(a-1)/2+2;
代码:
1 //Author: xiaowuga 2 #include <iostream> 3 #include <algorithm> 4 #include <set> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 #include <cstring> 9 #include <cstdio> 10 #include <ctime> 11 #include <map> 12 #include <bitset> 13 #include <cctype> 14 #define maxx INT_MAX 15 #define minn INT_MIN 16 #define inf 0x3f3f3f3f 17 #define mem(s,ch) memset(s,ch,sizeof(s)) 18 #define nc cout<<"nc"<<endl 19 #define sp " " 20 const long long N=100000; 21 using namespace std; 22 typedef long long LL; 23 typedef int II; 24 int main() { 25 ios::sync_with_stdio(false);cin.tie(0); 26 II T; 27 cin>>T; 28 II a; 29 while(T--){ 30 cin>>a; 31 cout<<(a-1)/2+2<<endl; 32 } 33 return 0; 34 }
HDU6125 Free from square
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6125
题目意思:1---n 选择不超过k个数,使得他们的乘积不包含完全平方因子
题目思路:分组背包+状态压缩(待补)
代码:
1 //Author: xiaowuga 2 #include <iostream> 3 #include <algorithm> 4 #include <set> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 #include <cstring> 9 #include <cstdio> 10 #include <ctime> 11 #include <map> 12 #include <bitset> 13 #include <cctype> 14 #define maxx INT_MAX 15 #define minn INT_MIN 16 #define inf 0x3f3f3f3f 17 #define mem(s,ch) memset(s,ch,sizeof(s)) 18 #define nc cout<<"nc"<<endl 19 #define sp " " 20 const long long N=505; 21 const long long mod=1e9+7; 22 using namespace std; 23 typedef long long LL; 24 typedef int II; 25 II p[8]={2,3,5,7,11,13,17,19}; 26 II n,k; 27 LL dp[N][N]; 28 II st[N],be[N]; 29 vector<int>v[N]; 30 void solve(){ 31 mem(dp,0); 32 dp[0][0]=1; 33 for(II i=1;i<=n;i++){ 34 v[i].clear();be[i]=i;st[i]=0; 35 } 36 37 for(II i=1;i<=n;i++) 38 for(II j=0;j<8;j++){ 39 if(st[i]!=-1&&i%p[j]==0&&i%(p[j]*p[j])!=0){ 40 st[i]|=(1<<j);be[i]/=p[j]; 41 } 42 else if(i%(p[j]*p[j])==0){//自己本身有平方因子不可选 43 st[i]=-1;break; 44 } 45 } 46 47 for(II i=1;i<=n;i++){ 48 if(st[i]!=-1){ 49 if(be[i]==1) v[i].push_back(i); 50 else v[be[i]].push_back(i); 51 } 52 } 53 54 for(II i=1;i<=n;i++){ 55 if(st[i]==-1||v[i].size()==0) continue; 56 57 for(II j=k-1;j>=0;j--) 58 for(II kk=0;kk<(1<<8);kk++) 59 for(II l=0;l<v[i].size();l++){ 60 II d=st[v[i][l]]; 61 if((kk&d)==0) dp[j+1][kk|d]=(dp[j+1][kk|d]+dp[j][kk])%mod; 62 } 63 } 64 LL ans=0; 65 for(II i=1;i<=k;i++){ 66 for(II j=0;j<(1<<8);j++) 67 ans=(ans+dp[i][j])%mod; 68 } 69 cout<<ans%mod<<endl; 70 } 71 int main() { 72 ios::sync_with_stdio(false);cin.tie(0); 73 II T; 74 cin>>T; 75 while(T--){ 76 cin>>n>>k; 77 solve(); 78 } 79 return 0; 80 }
HDU6127 Hard challenge
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6127
题目意思:平面坐标系,给出n个点,保证任意两点的连线不过原点. 每一个点都有一个权值,两点之间的线段的权值等于端点权值之积 ,问如果过原点做一条直线,直线穿过的线段的权值和最大是多少。
思路:极角排序(根据斜率),从小到大排序。没什么好讲了,以后多常来看看吧,极角排序这种思路第一次见到。具体见代码吧。
代码:
1 //Author: xiaowuga 2 #include <iostream> 3 #include <algorithm> 4 #include <set> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 #include <cstring> 9 #include <cstdio> 10 #include <ctime> 11 #include <map> 12 #include <bitset> 13 #include <cctype> 14 #define maxx INT_MAX 15 #define minn INT_MIN 16 #define inf 1e9+10; 17 #define mem(s,ch) memset(s,ch,sizeof(s)) 18 #define nc cout<<"nc"<<endl 19 #define sp " " 20 const long long N=50000+100; 21 using namespace std; 22 typedef long long LL; 23 typedef int II; 24 double eps=-1e-10; 25 struct P{ 26 LL x,y,v; 27 double k; 28 bool operator <(const P& m)const{ 29 return k<m.k; 30 } 31 }p[N]; 32 II n; 33 LL sum=0; 34 void solve(){ 35 double k=p[0].k; 36 LL s=0,s2=0; 37 for(II i=0;i<n;i++){ 38 if(p[i].x>=0) s+=p[i].v; 39 if(p[i].x>0) s2+=p[i].v; 40 } 41 LL ans=0; 42 ans=max(ans,(sum-s)*s); 43 ans=max(ans,(sum-s2)*s2); 44 for(II i=0;i<n;i++){ 45 if(p[i].x>=0) s-=p[i].v; 46 else s+=p[i].v; 47 ans=max(ans,(sum-s)*s); 48 } 49 cout<<ans<<endl; 50 } 51 int main() { 52 ios::sync_with_stdio(false);cin.tie(0); 53 II T; 54 cin>>T; 55 II x,y,v; 56 while(T--){ 57 cin>>n; 58 sum=0; 59 for(II i=0;i<n;i++){ 60 cin>>p[i].x>>p[i].y>>p[i].v; 61 if(p[i].x==0){ 62 if(p[i].y<0)p[i].k=-(1e9+7); 63 else p[i].k=1e9+7; 64 } 65 else p[i].k=1.0*p[i].y/p[i].x; 66 sum+=p[i].v; 67 } sort(p,p+n); 68 solve(); 69 } 70 return 0; 71 }
HDU6129 Just do it
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6129
题目意思:设定b【i】=a【1】^a【2】^a【3】^..................a【i】;每进行一次,我们可以从a数组得到一个b数组。问进行m次的结果。
题目思路:我们可以手推几项,我们就会发现ans[i][j]进行i次变换,前j项前缀异或和的的答案,很明显ans[i][j]=ans[i-1][j]+ans[i][j-1],我们发现这是一个稍微倾斜了一点的杨辉三角,百度了一下得到了结论对于第m行的第i项杨慧三角的系数为C(m+i-2,i-1),如果他是奇数那么第一个数对于第i个数是有贡献的,第二个数对于第i+1个数是有贡献的。对于如何判断系数是不是奇数我们可以通过(x&y)==y来判断(对应C(x,y))。
代码:
1 #include<stdio.h> 2 #include<string.h> 3 int n,m; 4 int a[500000+10]; 5 int ans[500000+10]; 6 int main() { 7 int T; 8 scanf("%d",&T); 9 while(T--){ 10 scanf("%d%d",&n,&m); 11 memset(ans,0,sizeof(ans)); 12 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 13 for(int i=1;i<=n;i++){ 14 int x=m+i-2,y=i-1; 15 if((x&y)==y){ 16 for(int j=i;j<=n;j++) ans[j]^=a[j-i+1]; 17 } 18 } 19 for(int i=1;i<=n;i++){ 20 printf("%d%c",ans[i],(i==n)?'\n':' '); 21 } 22 } 23 return 0; 24 }
HDU6130 Kolakoski
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6130
题目意思:一个打表题,自己百度一下这个奇怪的数列。然后根据定义打表就好了,不想多说什么,打表的时候可以使用双指针什么的。
代码:
1 //Author: xiaowuga 2 #include <iostream> 3 #include <algorithm> 4 #include <set> 5 #include <vector> 6 #include <queue> 7 #include <cmath> 8 #include <cstring> 9 #include <cstdio> 10 #include <ctime> 11 #include <map> 12 #include <bitset> 13 #include <cctype> 14 #define maxx INT_MAX 15 #define minn INT_MIN 16 #define inf 0x3f3f3f3f 17 #define mem(s,ch) memset(s,ch,sizeof(s)) 18 #define nc cout<<"nc"<<endl 19 #define sp " " 20 const long long N=1e7+10; 21 using namespace std; 22 typedef long long LL; 23 typedef int II; 24 II ans[N]; 25 int main() { 26 ios::sync_with_stdio(false);cin.tie(0); 27 ans[1]=1; 28 ans[2]=2; 29 ans[3]=2; 30 II l=3,ct=4; 31 while(ct<N-1){ 32 II a=ans[l++],b; 33 if(ans[ct-1]==1) b=2; 34 else b=1; 35 while(a--){ 36 ans[ct++]=b; 37 } 38 } 39 II n; 40 II T; 41 cin>>T; 42 while(T--){ 43 cin>>n; 44 cout<<ans[n]<<endl; 45 } 46 return 0; 47 }
代码: