比赛
The 2015 ACM-ICPC Asia Dhaka Regional Contest
A | B | C | D | E | F | G | H | I | J |
---|---|---|---|---|---|---|---|---|---|
Z | Y | **Y | Y | L | **Z | **L | **L | **Y | **Z |
题解
A
签到题,扫一遍统计一下
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
int T, n;
int cnt[12][3][3];
char s[5];
int main()
{
int d, l;
cin>>T;
while(T--){
long long ans = 0;
memset(cnt, 0, sizeof(cnt));
scanf("%d", &n);
for (int i = 1; i <= n; ++i){
scanf("%d%d%s", &d, &l, s);
cnt[d][l][s[0] == 'c']++;
}
for (int i = 2; i <= 10; ++i){
cnt[i][0][0] += cnt[i-1][0][0];
}
for (int i = 2; i <= 10; ++i)
ans += 1ll * cnt[i][1][1] * cnt[i - 1][0][0];
printf("%d\n", ans);
}
}
B
C
D
E
求一个集合,使得该集合所有元素的最小公倍数为
n
n
n,最大化集合中所有元素的和,有
T
T
T组数据。
答案明显是
1
1
1到
n
n
n所有数约数和的和。
- 直接埃氏筛,就可以过,复杂度 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)
- 直接线筛,复杂度 O ( n ) O(n) O(n)
- 推导一下
a
n
s
=
∑
i
=
2
n
∑
d
∣
i
d
=
∑
d
=
1
n
d
⌊
n
d
⌋
ans=\sum_{i=2}^{n}\sum_{d|i}d=\sum_{d=1}^{n}d\lfloor\frac{n}{d}\rfloor
ans=i=2∑nd∣i∑d=d=1∑nd⌊dn⌋
所以直接整数分块就可以了,复杂度 O ( T n ) O(T\sqrt n) O(Tn)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
#define inl inline
#define re register
#define MAXN 20000000
using namespace std;
LL t[20000101];
LL ans[MAXN+10];
int n;
int main()
{
for(int i=1;i<=MAXN;i++)
for(int j=i;j<=MAXN;j+=i)t[j]+=i;
for(int i=1;i<=MAXN;i++)
ans[i]=ans[i-1]+t[i];
while(scanf("%d",&n)!=EOF)
{
if(n==0)return 0;
printf("%lld\n",ans[n]-1);
}
return 0;
}
F
题意:求中位数大于h的最大矩形。
把大于等于h的数作为1, 小于h的数作为-1,问题转换为求一个最大的大于等于0的矩阵,很容易想到一个带log的做法,然后就会被出题人卡掉。所以有一个很妙的尺取法,求完前缀和后,考虑对每一个值,应该尽量的取左面的合法的值。所以先扫一遍求一个递减的序列,然后从右向左枚举每一个值,在数组中维护一个右端点,然后尽量取左面的点就可以了
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 300;
int R, C;
int q[N], a[N][N], pic[N][N];
int sum[N][N], pre[N];
inline void solve(){
memset(sum, 0, sizeof(sum));
for (int i = 1; i <= R; ++i){
for (int j = 1; j <= C; ++j)
sum[i][j] = pic[i][j] + sum[i-1][j];
}
}
inline int getans(int up, int down){
for (int i = 1; i <= C; ++i)
pre[i] = pre[i-1] + sum[down][i] - sum[up - 1][i];
int r = 0;
for (int i = 1; i <= C; ++i)
if (pre[i] < pre[q[r]]) q[++r] = i;
int ans = 0;
for (int i = C; i; i--){
while(r && pre[q[r - 1]] <= pre[i]) r--;
if (pre[q[r]] <= pre[i]) ans = max(ans, (down - up + 1) * (i - q[r]));
}
return ans;
}
int main()
{
int h, q, T, ans;
cin>>T;
for (int p = 1; p <= T; ++p){
printf("Case %d:\n", p);
scanf("%d%d", &R, &C);
for (int i = 1; i <= R; ++i)
for (int j = 1; j <= C; ++j)
scanf("%d", &a[i][j]);
scanf("%d", &q);
for (int i = 1; i <= q; ++i){
ans = 0;
scanf("%d", &h);
for (int j = 1; j <= R; ++j)
for (int k = 1; k <= C; ++k)
pic[j][k] = a[j][k] >= h ? 1 : -1;
solve();
for (int up = 1; up <= R; ++up)
for (int dn = up; dn <= R; ++dn)
ans = max(ans, getans(up, dn));
printf("%d\n", ans);
}
}
}
G
H
本质上是求中位数。
前置,已知一维数轴点集
{
a
n
}
\{a_n\}
{an},求使得曼哈顿距离之和的最小的点的位置:
- 如果 n n n是奇数,那么应该取 a n 2 a_{\frac n2} a2n
- 如果 n n n是偶数,那么取 [ a n 2 , a n 2 + 1 ] [a_{\frac n2}, a_{\frac{n}{2}+1}] [a2n,a2n+1]中的任何一个数,得到的曼哈顿距离之和相等且最小
如果在其他高维坐标下求解点的位置,由于每一维坐标互不干扰,直接分别计算即可。
显然在本题,当
n
n
n是奇数的时候,答案肯定为
0
0
0,当
n
n
n是偶数的时候,稍微推一下式子然后发现是可以卷积的,直接
N
T
T
NTT
NTT即可
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define LL long long
#define inl inline
#define re register
#define MAXN 101000
using namespace std;
const LL mod=7340033;
LL poww(LL i,LL k)
{
if(k<0||i==0)return 0;
LL ans=1;
for(;k;k>>=1,i=(i*i)%mod)if(k&1)ans=(ans*i)%mod;
return ans;
}
LL invv(LL i){return poww(i,mod-2);}
LL fac[MAXN];
LL C(int m,int n){return m<=n?(fac[n]*invv((fac[m]*fac[n-m])%mod))%mod:0;}
LL R[MAXN<<2],BIT,ml,g=3;
int lsn;
void ntt(LL *a,int n,int inv)
{
if(lsn!=n&&(lsn=n))
for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(BIT-1));
for(int i=0;i<n;i++)if(i<R[i])swap(a[i],a[R[i]]);
for(int i=1;i<n;i<<=1)
{
LL mi=(inv==1)?poww(g,(mod-1)/(i<<1)):invv(poww(g,(mod-1)/(i<<1)));
for(int j=0;j<n;j+=(i<<1))
{
LL x=1;
for(int k=0;k<i;k++,x=(x*mi)%mod)
{
LL t1=a[j+k],t2=(x*a[j+k+i])%mod;
a[j+k]=(t1+t2)%mod,a[j+k+i]=((t1-t2)%mod+mod)%mod;
}
}
}
if(inv==-1)for(int i=0;i<n;i++)a[i]=(a[i]*invv(n))%mod;
}
int a,b,c,d,n;
LL A[MAXN<<2],B[MAXN<<2];
LL ans[MAXN];
int main()
{
LL x,y;
int T;cin>>T;
fac[0]=1;
for(int i=1;i<=MAXN-11;i++)fac[i]=fac[i-1]*i%mod;
for(int u=1;u<=T;u++)
{
scanf("%d",&n);
for(ml=1,BIT=0;ml<=2*n;ml<<=1,BIT++);
for(int i=0;i<=ml;i++)A[i]=B[i]=0;
a=b=c=d=0;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&x,&y);
if(x>0&&y>0)a++;
if(x<0&&y>0)b++;
if(x<0&&y<0)c++;
if(x>0&&y<0)d++;
}
for(int i=0;i<=n;i++)A[i]=C(i,a)*C(i,c)%mod;
for(int i=0;i<=n;i++)B[i]=C(i,b)*C(i,d)%mod;
ntt(A,ml,1),ntt(B,ml,1);
for(int i=0;i<ml;i++)A[i]=A[i]*B[i]%mod;
ntt(A,ml,-1);
printf("Case %d:\n",u);
for(int i=1;i<=n;i++)
{
if(i&1)ans[i]=0;
else ans[i]=A[i/2];
}
for(int i=1;i<=n;i++)
{
printf("%lld%c",ans[i],(i==n)?'\n':' ');
}
}
return 0;
}
*/
I
J
统计阿基米德螺旋线中几块的面积,一开始积分积错了,推出式子之后细节写挂了,几个细节就是考虑从第n条线到第1条线的面积,还有第一圈里面的面积,这两种情况要考虑一下,改了好久
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
double ar;
const double pi=acos(-1);
double ccal(double th1,double th2,int T)
{
th1 = max(th1 + 2 * pi * T, 0.), th2 = max(th2 + 2 * pi * T, 0.);
return ar * ar * (th2*th2*th2 - th1*th1*th1)/6;
}
double cal(double th1,double th2,int T)
{
return fabs(ccal(th1,th2,T)-ccal(th1,th2,T-1));
}
double th[20];
struct shape{
double th1, th2;
int T;
}ts[1010];
inline int cmp(const shape &a, const shape &b){return a.th1 == b.th1? a.T < b.T : a.th1 < b.th1;}
int main()
{
int n, m, T;
cin>>T;
for (int k = 1; k <= T; ++k){
double pt, pr, th1, th2, ans = 0;
scanf("%lf", &ar);
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%lf", &th[i]);
sort(th + 1, th + n + 1);
th[n + 1] = th[1] + 2 * pi;
scanf("%d", &m);
for (int i = 1; i <= m; ++i){
scanf("%lf%lf", &pr, &pt);
if (pt < th[1]) th1 = th[n], th2 = th[n+1];
else for (int j = 1; j <= n; ++j) {
if (pt > th[j] && pt < th[j + 1]) {
th1 = th[j], th2 = th[j + 1];
break;
}
}
int l = 0, r = 1000000, res = 0;
while(l <= r){
int mid = (l + r) >> 1;
if (ar * (2 * pi * mid + pt) > pr) res = mid, r = mid - 1;
else l = mid + 1;
}
if (th1 == th[n] && pt < th[1]) ts[i] = (shape){th1, th2, res - 1};
else ts[i] = (shape){th1, th2, res};
}
sort(ts + 1, ts + m + 1, cmp);
for (int j = 1; j <= m; ++j){
if (ts[j].th1 == ts[j-1].th1 && ts[j].T == ts[j-1].T) continue;
else ans += cal(ts[j].th1, ts[j].th2, ts[j].T);
}
ans = ans / 10;
if (n == 0) printf("Spiral %d: -1\n", k);
else printf("Spiral %d: %.4f liters\n", k, ans);
}
return 0;
}