送分题,菜到考场上没 $A$。
$sort$ $+$ $set$ 无脑组合。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
using namespace std;
const int maxn = 1e4 + 10;
int n; string str;
set<string> s;
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
for (int i = 1; i <= n; i++){
cin >> str; sort(str.begin(),str.end());
s.insert(str);
}
cout << s.size() << endl;
return 0;
}
T2
考试时在这题肝了好久。
看到相似三角形,果断想到相似比。设相似比为 $a:b:c$,
那么三角形就都可以表示出来:$(p_1a,p_1b,p_1c)$, $(p_2a,p_2b,p_2c)$, …, $(p_xa,p_xb,p_xc)$。
这时可以得出式子,$(a+b+c) times sum_{i=1}^{x}p_i = n$。
如果能知道 $(a+b+c)$,就能得到 $sum_{i=1}^{x}p_i$,而 $p$ 的分配方案就是本题的答案。
那如何知道 $(a+b+c)$ 呢?考场上的时间所限,没有再展开思考,用了三重枚举。但直接枚举会导致重复,如 $(1,1,1)$ 与 $(2,2,2)$。后来发现当三个数互质时,这个相似比是同比例中第一个出现的。
这时题目变成了给定一个数($sum_{i=1}^{x}p_i$),求用一些数之和($p_1,p_2,…,p_x$)表示的方案数有多少。(类似于洛谷 P1025)
下面是考场代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
int n,ans;
inline bool check(int a, int b, int c){
return a+b>c && a+c>b && b+c>a && n%(a+b+c) == 0;
}
int gcd(int a, int b){
return !b ? a : gcd(b,a%b);
}
int poww(int base, int k){
if (k == 0) return 1;
if (k == 1) return base;
int p = poww(1ll*base*base%mod,k>>1);
if (k&1) return p * base % mod;
else return p % mod;
}
int main(){
scanf("%d",&n);
for (int a = 1; a <= n; a++)
for (int b = a; b <= n; b++)
for (int c = b; c <= n; c++){
if (a + b + c > n || !check(a,b,c)) continue;
int p = gcd(a,b); if (gcd(p,c) > 1) continue;
ans += poww(2,n/(a+b+c)-1);
if (ans > mod) ans %= mod;
}
printf("%dn",ans);
return 0;
}
不出所料,得到了 $60pts$。
回家后参照着网上的题解进行优化。
不妨设 $a leq b leq c$,用 $f[i]$ 表示相似比之和为 $i$ 的不同组合有几个。
考虑转移,可以分开两种情况计算:
- $a leq b = c$。显然这时 $b,c$ 是有上下界的,不难得出 $lceil frac{i}{3} rceil leq b,c leq lfloor frac{i-1}{2} rfloor$。
- $a leq b lt c to a leq b leq c-1$。不难发现这时就是 $f[i-1]$。当然,事情没有这么简单。若我们原本的 $a + b = c$,这时构不成三角形,但若转移到 $a leq b leq c-1$,就满足了 $a + b = c > c-1$。换句话说,我们转移过去的时候,把本来构不成三角形的 $a+b=c$ 的情况算了进去。根据容斥原理,现在我们要再减下去。当 $a+b=c$ 时,$i = a+b+c = 2 times (a+b)$,由此可得 $a in [1,frac{i}{4}]$。同时可以注意到,只有当 $i$ 为偶数时才会出现这种情况。
另外,不要忘记把 $f[i]$ 中所有计算过的三角形削去。而这些三角形的数量,正是 $sum f[p] : : (p mid i)$。
下面是正解代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
int n,i,f[maxn],m[maxn]; ll ans;
int quickPow(int base, int k){
if (k == 0) return 1;
if (k == 1) return base;
int p = quickPow(1ll*base*base%mod,k>>1);
if (k&1) return 1ll * p * base % mod;
else return p % mod;
}
int main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
scanf("%d",&n); f[3] = 1;
for (i = 4; i <= n; i++){
f[i] = f[i-1] + ((i-1)>>1) - ceil(i/3.0) + 1;
if (!(i&1)) f[i] -= (i>>2);
if (f[i] >= mod) f[i] %= mod;
if (f[i] < 0) f[i] += mod;
}
for (i = 2; i <= n; i++)
for (int j = 2; i*j <= n; j++){
f[i*j] -= f[i];
if (f[i*j] < 0)
f[i*j] += mod;
}
for (i = 1; i*i < n; i++){
if (n % i) continue;
ans += 1ll * f[i] * quickPow(2,n/i-1);
if (ans >= mod) ans %= mod;
ans += 1ll * f[n/i] * quickPow(2,i-1);
if (ans >= mod) ans %= mod;
}
if (i*i == n)
ans += 1ll * f[i] * quickPow(2,i-1);
printf("%lldn",ans%mod);
return 0;
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]。
近期评论