2018 Multi-University Training Contest 4
累惹。
B. Harvest of Apples
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6333
题意:求∑(i=0,m) C(n,m)。
分析:定义S(n,m)=∑(i=0,m) C(n,m)。可以知道:
S(n,m)=S(n,m-1)+C(n,m),S(n-m)=S(n-1,m-1)+S(n-1,m)=2*S(n-1,m-1)+C(n-1,m)。
由此可以推导出,由S(n,m)到S(n-1,m),S(n+1,m),S(n,m-1),S(n,m+1)的式子为:
S(n-1,m)=(S(n,m)+C(n-1,m))/2
S(n+1,m)=2*S(n,m)-C(n,m)
S(n,m-1)=S(n,m)-C(n,m)
S(n,m+1)=S(n,m)+C(n,m+1)
得到了四个方向的状态转移式,因此,可以用莫队离线处理。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 const int mod=1e9+7; 5 typedef long long ll; 6 struct point{ 7 int n,m,block,id; 8 }q[maxn]; 9 ll fac[maxn],inv[maxn],ans[maxn]; 10 int res,Block; 11 void init(){ 12 inv[0]=inv[1]=1; 13 for (int i=2;i<maxn;i++) 14 inv[i]=(mod-mod/i)*inv[mod%i]%mod; 15 } 16 int comp(point p,point q){ 17 return p.block<q.block || p.block==q.block && p.m<q.m; 18 } 19 20 int main(){ 21 init(); 22 int t; 23 cin >> t; 24 Block=(int)(sqrt(t)); 25 for (int i=0;i<t;i++){ 26 cin >> q[i].n >> q[i].m; 27 q[i].id=i; 28 q[i].block=q[i].n/Block; 29 } 30 sort(q,q+t,comp); 31 ll n=0,m=0,nc=1,res=1; 32 for (int i=0;i<t;i++){ 33 int nn=q[i].n,nm=q[i].m; 34 while (nn<n){ 35 nc=nc*(n-m)%mod*inv[n]%mod; 36 res=(res+nc)%mod*inv[2]%mod; 37 n--; 38 } 39 while (nn>n){ 40 res=(res*2%mod-nc+mod)%mod; 41 nc=nc*(n+1)%mod*inv[n+1-m]%mod; 42 n++; 43 } 44 while (nm<m){ 45 res=(res-nc+mod)%mod; 46 nc=nc*m%mod*inv[n-m+1]%mod; 47 m--; 48 49 } 50 while (nm>m){ 51 nc=nc*(n-m)%mod*inv[m+1]%mod; 52 res=(res+nc)%mod; 53 m++; 54 } 55 ans[q[i].id]=res; 56 } 57 for (int i=0;i<t;i++) cout << ans[i] << endl; 58 return 0; 59 }
D. Nothing is Impossible
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6335
题意:有若干道题,每题有1个正确选项,b个错误选项,问一个最优决策使得winner得分最大。
分析:如果仅有 1 道题,至少有一个人做对这题需要有 错误答案个数 + 1 个人。那么容易发现在每道题正确答案只有一个的情况下,如果 nn 道题中存在 ss 道题,使得学生人数 mm 不少于每道题 错误答案个数 + 1 相乘的结果,那么一定有人能够得到 ss 分。故我们将题目按错误答案个数从小到大排序,找到最大的 pp 满足就是答案。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=110; 4 struct node{int a,b,num;}a[N]; 5 bool cmp(node a,node b){return a.num<b.num;} 6 int main(){ 7 int t,n,m;scanf("%d",&t); 8 while(t--){ 9 scanf("%d%d",&n,&m); 10 for(int i=1;i<=n;i++) scanf("%d%d",&a[i].a,&a[i].b),a[i].num=a[i].a+a[i].b; 11 sort(a+1,a+n+1,cmp); 12 int tmp=m;int cnt=-1; 13 for(int i=1;i<=n;i++){ 14 int num=a[i].num; 15 int nn=tmp/num; 16 tmp=nn*a[i].a; 17 if(tmp<1) break; 18 cnt=i; 19 } 20 printf("%d\n",cnt); 21 } 22 return 0; 23 }
E. Matrix from Arrays
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6336
题意:根据题意构造一个矩阵,求子矩阵和。
分析:打表发现矩阵有循环节。n为奇数时循环节为n*n,n为偶数时循环节为2*n*2*n。求出循环节二维前缀和,再扩展到普通矩阵求和即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstring> 3 #define maxn 500 4 using namespace std; 5 typedef long long ll; 6 int mp[maxn][maxn],a[maxn]; 7 int L; 8 void init(){ 9 int cursor = 0; 10 for (int i = 0;i<4*L; ++i) { 11 for (int j = 0; j <= i; ++j) { 12 mp[j][i - j] = a[cursor]; 13 cursor = (cursor + 1) % L; 14 } 15 } 16 L*=2; 17 for (int i=0;i<L;i++) 18 for (int j=0;j<L;j++){ 19 if (i) mp[i][j]+=mp[i-1][j]; 20 if (j) mp[i][j]+=mp[i][j-1]; 21 if (i && j) mp[i][j]-=mp[i-1][j-1]; 22 } 23 } 24 ll calc(int x,int y){ 25 if (x<0 || y<0) return 0; 26 ll res=0; 27 res=1ll*mp[L-1][L-1]*(x/L)*(y/L)+1ll*mp[x%L][L-1]*(y/L)+1ll*mp[L-1][y%L]*(x/L)+1ll*mp[x%L][y%L]; 28 return res; 29 } 30 ll slove(){ 31 int l1,r1,l2,r2; 32 ll res=0; 33 cin >> l1 >> r1 >> l2 >> r2; 34 res=calc(l2,r2)-calc(l1-1,r2)-calc(l2,r1-1)+calc(l1-1,r1-1); 35 return res; 36 } 37 int main(){ 38 ios::sync_with_stdio(false); 39 cin.tie(0);cout.tie(0); 40 int t,q; 41 cin >> t; 42 while (t--){ 43 cin >> L; 44 for (int i=0;i<L;i++) cin >> a[i]; 45 init(); 46 cin >> q; 47 while (q--){ 48 ll ans=slove(); 49 cout << ans << endl; 50 } 51 } 52 return 0; 53 }
K. Expression in Memories
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6342
题意:在?处填入数字0-9或+,*使得表达式合法。
分析:填入1或+即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 bool is1(char c){ 4 return c=='+'||c=='*'; 5 } 6 int main(){ 7 std::ios::sync_with_stdio(false); 8 int t;string s;cin>>t; 9 while(t--){ 10 cin>>s;s='+'+s;int len=s.size(); 11 for(int i=1;i<len;i++){ 12 if(s[i]=='?'){ 13 if(s[i-1]=='0'&&(s[i-2]=='+'||s[i-2]=='*')) s[i]='+'; 14 else s[i]='1'; 15 } 16 } 17 int flag=1; 18 for(int i=1;i<len;i++){ 19 if(is1(s[i])&&is1(s[i-1])) flag=0; 20 if(i==len-1) break; 21 if(is1(s[i-1])&&s[i]=='0'&&!is1(s[i+1])) flag=0; 22 } 23 string ans=""; 24 for(int i=1;i<len;i++) ans+=s[i]; 25 if(is1(s[len-1])) flag=0; 26 if(flag) cout<<ans<<"\n"; 27 else cout<<"IMPOSSIBLE"<<"\n"; 28 } 29 return 0; 30 }
L. Graph Theory Homework
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6343
题意:起点1,终点n,中间可经过任意点。求1-n的最小距离。
分析:容易证明:|sqrt(a)| + |sqrt(b)| > |sqrt(a+b)| ,边权满足三角不等式,故直接从1-n距离最小。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #define maxn 100005 5 using namespace std; 6 int a[maxn]; 7 int main(){ 8 ios::sync_with_stdio(false); 9 cin.tie(0);cout.tie(0); 10 int t,n; 11 cin >> t; 12 while (t--){ 13 cin >> n; 14 for (int i=1;i<=n;i++) cin >> a[i]; 15 int ans=(int)sqrt(abs(a[1]-a[n])); 16 cout << ans << endl; 17 } 18 return 0; 19 }