B. The Difference
水题,暴力跑一边permutation
G. The Mountain
水题,直接用叉积算一发面积
#include <bits/stdc++.h>
#include<cstring>
using namespace std;
#define ll long long
const int maxn = 201;
struct Point
{
double x,y;
Point(){}
Point(double _x,double _y)
{
x = _x;
y = _y;
}
double operator ^(const Point &b) const
{
return x*b.y - y * b.x;
}
};
struct polygon
{
int n;
Point p[maxn];
double getarea()
{
double sum = 0;
for(int i = 0;i<n;i++)
{
sum += (p[i]^p[(i+1)%n]);
}
return fabs(sum)/2;
}
};
int main()
{
//freopen("input.txt","r",stdin);
int T,cat = 1;
cin>>T;
while(T--)
{
polygon pl;
cin>>pl.n;
for(int i = 0;i<pl.n;i++)
{
cin>>pl.p[i].x>>pl.p[i].y;
}
cout<<setprecision(6)<<fixed<<pl.getarea()<<endl;
}
return 0;
}
D. Fence Building
把一个圆用k个点分成最多的区域是多少?
我们考虑二维欧拉公式1 = V-E+F 其中V代表点,E代表边,F代表面。
在院内,每四个点之间的形成一个面上的点,每两个点形成一条边,那么我们利用这个公式可以直接求出面的个数,也就是答案。
取模很是麻烦,稳妥起见。每次运算都要取模
#include <bits/stdc++.h>
#include<cstring>
using namespace std;
#define ll long long
#define mod 1000000007
long long pow_mod(long long a,long long n,long long m)//a^n mod m
{
a%=mod;
long long res=1ll;
while(n>0)
{
if(n&1==1)
res=res*a%m;
a=a*a%m;
n>>=1;
}
return res;
}
//记得在最后输出结果的时候再模m一次
ll quick_inverse(ll n, ll p) //传入a和mod-2,即quick_inverse(a,mod-2)
//返回a关于mod的逆元
{
ll ret = 1,exponent = p;
for (ll i = exponent; i; i >>= 1, n = n * n % mod)
if (i & 1)
ret = ret * n % mod;
return ret;
}
int main()
{
//freopen("input.txt","r",stdin);
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
ll n;
scanf("%lld",&n);
ll ans=(((((((n%mod)*((n-1)%mod))%mod)*((n-2)%mod))%mod)*((n-3)%mod))%mod+((((((n-1)%mod)*((n-2)%mod))%mod)*12)%mod)%mod+(24*(n%mod))%mod)%mod;
while(ans<0)ans+=mod;
ans%=mod;
ans*=quick_inverse(24ll,mod-2)%mod;
ans%=mod;
printf("Case #%d: %lld\n",cas,ans);
}
return 0;
}
K. Sum of the Line
题意是有点麻烦,实际上就是求一个后缀和。
然后我们把这个写成一个式子:
a
n
s
i
=
∑
j
n
j
2
∗
[
g
c
d
(
i
,
j
)
=
1
]
ans_i = \sum_{j}^{n}j^2*[gcd(i,j) = 1]
ansi=∑jnj2∗[gcd(i,j)=1]
我们这样去理解,这个答案就是所有和n不互质的数的平方和,那么我们可以利用容斥原理:首先抛开gcd的影响,求出结果,对于每个质因子,我们减去或者加上这个质因子的贡献。
那么还要解决如何计算贡献的问题。我们知道
∑
i
n
i
2
=
n
(
n
+
1
)
(
2
n
+
1
)
6
\sum_{i}^{n} i^2= {n(n+1)(2n+1)\over 6}
∑ini2=6n(n+1)(2n+1),现在一开始的总和求出来了,枚举所有因子组合,我们要计算的平方和无论如何都能提出来这个因子的平方和,那么剩下的又变成了1^2 + 2^2 + 3^2…
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const ll mod = 998244353;
void getPrime()
{
}
ll pow_mod(ll a,ll n)
{
a %= mod;
ll res = 1;
while(n)
{
if(n & 1) res = res * a % mod;
a = a* a % mod;
n >>= 1;
}
return res;
}
vector<int> prime;
ll inv6;
ll func(ll n)
{
return ((n * (n+1)% mod ) * (2*n % mod + 1)% mod) *inv6 % mod;
}
int main()
{
inv6 = pow_mod(6,mod-2);
int ca;
cin>>ca;
while(ca--)
{
ll n,k;
cin>>n;
k = n;
prime.clear();
for(ll i = 2;i*i<=n;i++)
{
if(k % i == 0)
{
prime.push_back(i);
while(k % i == 0) k /= i;
}
}
if(k != 1) prime.push_back(k);
//for(int x : prime) cout<<x<<' '; cout<<endl;
ll ans =0;
int tot = prime.size();
for(int i = 0;i<(1<<tot);i++)
{
int cnt = 0;ll den = 1LL;
for(int j = 0;j<tot;j++)
{
if(i & (1<<j))
{
den *= (ll)prime[j];
cnt++;
}
}
if(cnt % 2 )
{
ans = (ans - ((den * den % mod) * func(n/den) )% mod + mod) % mod;
}
else ans = (ans + (den * den % mod) * func(n/den)) % mod;
}
cout<<ans<<endl;
}
return 0;
}
I. A Possible Tree
一道带权并查集题放到了树上……
简要地说就是如果两个点之间的路径已经在一个关系里了,如果着一条路径不满足条件,说明已经到头了,如果能满足的话,就把这一次的结果叠加上去
#include <bits/stdc++.h>
#define ll long long
#define find fuck
#define next fuckme
using namespace std;
const int MAXN = 1e5 + 5;
int f[MAXN],sum[MAXN];
int find(int x)
{
if(x == f[x]) return f[x];
else
{
int fx = find(f[x]);
sum[x] ^= sum[f[x]];
return f[x] = fx;
}
}
void init(int n)
{
for(int i = 0;i<=n;i++)
{
f[i] = i;
sum[i] = 0;
}
}
int n,q;
int main()
{
int ca;
scanf("%d",&ca);
while(ca--)
{
scanf("%d%d",&n,&q);
init(n);
for(int i = 0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
}
int ans = q+1;
for(int i = 1;i<=q;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
if(ans != q+1) continue;
int fv =find(v);
int fu = find(u);
if(fv == fu && (sum[v] ^ sum[u]) != w)
{
ans = i;
}
else
{
f[fu] = fv;
sum[fu] = sum[v] ^ sum[u] ^ w;
}
}
printf("%d\n",ans-1);
}
return 0;
}