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
浙公网安备 33010602011771号