WHUST 2015 Summer Contest #0.1
A - Queries on the Tree
题意: 根节点为1的一棵树,有两种类型的操作,第一种是1 L Y, 把距离根节点L的结点值增加Y, 2 X, 查询以X为跟的子树的和。
思路: 1. 使用DFS搞成区间序列的形式 2. 对于操作1,把这个结点深度的值存储下来,依次增加(!) 3. 对于操作2,明显是一个区间和查询。
根据上述思路, 这不就是一个普通的区间和的东西吗?
但是,有一个问题, 在思路2那里,如果真的依次增加, 那么一定会超时的。 这个时候可以进行分块, 把深度为L的结点进行分块操作。 快内的依次暴力解决, 然后快外的再依次解决。
#include <bits/stdc++.h> #define LL long long using namespace std; const int M = 1000; const int N = 100007; vector<int> pos[N],e[N],c; LL b[N],s[N]; int l[N],r[N],lst[N],cnt=0,n; void add(int x,LL v) {for (;x<=n;x+=x&(-x)) b[x]+=v;} LL sum(int x) {LL ans=0;for (;x;x-=x&(-x)) ans+=b[x];return ans;} void dfs(int x,int d) { lst[++cnt]=x; l[x]=cnt; pos[d].push_back(cnt); for (auto &p:e[x]) dfs(p,d+1); r[x]=cnt; } int main() { int m,x,y; scanf("%d%d",&n,&m); for (int i=0;i<n-1;++i) { scanf("%d%d",&x,&y); e[x].push_back(y); } dfs(1,0); for (int i=0;i<n;++i) if (pos[i].size()>M) c.push_back(i); for (int i=0;i<m;++i) { scanf("%d",&x); if (x==1) { scanf("%d%d",&x,&y); if (pos[x].size()<=M) for (auto &p:pos[x]) add(p,y); else s[x]+=y; } else { scanf("%d",&x); LL ans=sum(r[x])-sum(l[x]-1); for (auto &p:c) ans+=(upper_bound(pos[p].begin(),pos[p].end(),r[x]) -lower_bound(pos[p].begin(),pos[p].end(),l[x]))*s[p]; cout << ans << endl; } } return 0; }
B - Count Palindromes
水题: 问从t1到t2时刻,中间有几个时刻构成的字符串是回文的。
#include<bits/stdc++.h> using namespace std; int f[100000]; void init() { for (int h=0;h<=24;h++) for (int m=0;m<60;m++) for (int s=0;s<60;s++) { int t=h*3600+m*60+s+1; if (h/10==s%10&&h%10==s/10&&m/10==m%10) f[t]=f[t-1]+1; else f[t]=f[t-1]; } } int main() { int T,h1,m1,s1,h2,m2,s2; init(); scanf("%d",&T); while(T--) { scanf("%d:%d:%d",&h1,&m1,&s1); scanf("%d:%d:%d",&h2,&m2,&s2); int t1=h1*3600+m1*60+s1+1; int t2=h2*3600+m2*60+s2+1; printf("%d\n",f[t2]-f[t1-1]); } return 0; }
C - Find P'th Number
水题:去掉奇数问第p小的数或者去掉偶数问第p小的数字
#include<bits/stdc++.h> using namespace std; int n,p,ans; char s[10]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%s%d",&n,s,&p); if (s[0]=='o') ans=2*p; else ans=2*p-1; printf("%d\n",ans); } return 0; }
D - Desolation of Smaug
E - Count Distinct Sets
F - Count Ways
题意:问从(1,1) 到(n,m)有多少种走法,只能向下或者向右, 并且有k个点不能走。
思路:第一个重要的点, 得需要知道从(1,1)到(n,m), 假设中间没有障碍点,一共有C(n+m-2,n-1)种走法(最重要)。
假设x1,y1为障碍点, 那么到达x2,y2的走法应该是C(x2+y2-2,x2-1)-C(x1+y1-2,x1-1)*C(x2-x1+y2-y2,x2-x1) 也就是看成中间那个从x1,y1到x2,y2的小矩形。
计算C需要用到乘法逆元。
#include<bits/stdc++.h> #define N 200010 #define LL long long const LL MOD=1e9+7; using namespace std; struct node { int x,y; }; node a[N]; LL p[N],q[N]; LL f[N]; LL x,y,gcd; void ex_gcd(LL a, LL b) { if (!b) {x=1; y=0; gcd=a;} else {ex_gcd(b,a%b); LL temp=x; x=y; y=temp-a/b*y;} } void init() { q[0]=1; p[0]=1; for (int i=1;i<N;i++) { p[i]=p[i-1]*i%MOD; ex_gcd(i,MOD); while(x<0) x+=MOD; q[i]=q[i-1]*x%MOD; } } bool cmp(node a, node b) { return (a.x<b.x)||(a.x==b.x&&a.y<b.y); } LL C(int x, int y) { return p[x]*q[y]%MOD*q[x-y]%MOD; } int main() { int T,n,m,k; init(); scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); for (int i=0;i<k;i++) scanf("%d%d",&a[i].x,&a[i].y); a[k].x=n; a[k++].y=m; sort(a,a+k,cmp); for (int i=0;i<k;i++) f[i]=C(a[i].x+a[i].y-2,a[i].x-1); for (int i=0;i<k;i++) for (int j=0;j<i;j++) if (a[j].y<=a[i].y) { f[i]=(f[i]+MOD-f[j]*C(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)%MOD)%MOD; } printf("%I64d\n",f[k-1]); } return 0; }
G - Count Permutations
题意:问从1到N的排列中, 相邻数字差的绝对值不大于K的有多少种排列。
使用位运算的第i位来表示i是否使用过。然后DP
#include<bits/stdc++.h> #define N 40000 #define LL long long using namespace std; LL f[N][20]; int main() { int T,n,k; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&k); memset(f,0,sizeof(f)); for (int i=1;i<=n;i++) f[1<<(i-1)][i]=1; for (int s=1;s<(1<<n);s++) for (int i=1;i<=n;i++) if ((s>>(i-1))&1) { for (int j=max(1,i-k);j<=min(n,i+k);j++) if (i!=j&&((s>>(j-1))&1)) f[s][i]+=f[s^(1<<(i-1))][j]; } LL ans=0; for (int i=1;i<=n;i++) ans+=f[(1<<n)-1][i]; printf("%I64d\n",ans); } return 0; }
H - Count Subarrays
题意:问在序列1……N中有多少个连续子序列中的逆序对数不少于K。
从左端点开始,逆序对数是单调递增的。于是可以维护一个右端点。
注意 使用upper_bound 一定需要注意范围!
#include<bits/stdc++.h> #define N 100010 #define LL long long using namespace std; int a[N],b[N]; int n,m; LL k; LL d[N]; int lowbit(int x) { return x&(-x); } void update(int x, int num) { while(x<=m) { d[x]+=num; x+=lowbit(x); } } LL sum(int x) { LL s=0; while(x>0) { s+=d[x]; x-=lowbit(x); } return s; } int main() { LL ans,t; while(scanf("%d%I64d",&n,&k)!=EOF) { ans=0; for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=0;i<n;i++) b[i]=a[i+1]; sort(b,b+n); m=unique(b,b+n)-b; for (int i=1;i<=m;i++) d[i]=0; for (int i=1;i<=n;i++) a[i]=lower_bound(b,b+m,a[i])-b+1; int j=0; t=0; for (int i=1;i<=n;i++) { if (j<i) { update(a[++j],1);t=0;} while(t<k&&j<n) { update(a[++j],1); t=t+sum(m)-sum(a[j]); } if (t>=k&&j<=n) ans=ans+n-j+1; t=t-sum(a[i]-1); update(a[i],-1); } printf("%I64d\n",ans); /* LL L=1,num=0; for (int i=1;i<=n;i++) { num+=sum(m)-sum(a[i]); update(a[i],1); if (num>=k) ans=ans+L; while(num>=k && L<i) { LL tp=sum(a[L]-1); if (num-tp>=k) { num-=tp; update(a[L],-1); L++; ans++; } else break; } } printf("%I64d\n",ans);*/ } return 0; }
I - Laughing Out Loud
水题
#include<bits/stdc++.h> #define N 100010 #define LL long long char s[N]; LL L[N],O[N]; using namespace std; int main() { int T,len; LL ans; scanf("%d",&T); while(T--) { ans=0; scanf("%s",s); len=strlen(s); O[0]=L[0]=0; for (int i=0;i<len;i++) { if (s[i]=='L') L[i+1]=L[i]+1; else L[i+1]=L[i]; if (s[i]=='O') O[i+1]=O[i]+L[i]; else O[i+1]=O[i]; } for (int i=0;i<len;i++) if (s[i]=='L') { ans=ans+O[i+1]; } printf("%I64d\n",ans); } return 0; }
J - Three Sorted Arrays
题意 1 ≤ i ≤ j ≤ k, such that: A[i] ≤ B[j] ≤ C[k]. 存在多少对这样的情况
二分和前缀和的应用
#include<bits/stdc++.h> #define N 100010 #define LL long long using namespace std; LL a[N],b[N],c[N]; LL f[N]; int main() { int T,p,q,r; LL ans; scanf("%d",&T); while(T--) { scanf("%d",&p); for (int i=1;i<=p;i++) scanf("%I64d",&a[i]); scanf("%d",&q); for (int i=1;i<=q;i++) scanf("%I64d",&b[i]); scanf("%d",&r); for (int i=1;i<=r;i++) scanf("%I64d",&c[i]); f[0]=0; ans=0; for (int i=1;i<=q;i++) { int j=lower_bound(c+i,c+r+1,b[i])-c; if (j<=r) f[i]=f[i-1]+(LL)(r-j+1); else f[i]=f[i-1]; } for (int i=1;i<=p;i++) { int j=lower_bound(b+i,b+q+1,a[i])-b; if (j<=q) ans=ans+f[q]-f[j-1]; } printf("%I64d\n",ans); } return 0; }
K - Police Catching Thief