题目链接: http://codeforces.com/contest/900
D题意:给出x, y,求满足下列2个条件的序列数目。
1.Σni=1ai=y
2.gcd(a1,a2,...,an)=x
题解:首先易知,y % x != 0, 则一定不存在这样的数列,答案为0。
否则数列每个数都除去x,可以转化为求有多少个数列满足gcd为1且和为
yx
。
设 f(t) 为有多少个数列满足gcd为1且和为 t 。
设 g(t) 为有多少个数列满足和为 t 。
可以得到下式:
g(t)=∑d|tf(td)
解法一:记忆化搜索, 直接计算
f(t)
,其中算的时候要容斥一下,初始隔板法想一下便知
mp[x]=2t−1,减去他因子的mp[d]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1E9 + 7;
map<int, int>mp;
ll quick(ll a, ll k) //a^k^mod
{
ll res = 1;
while(k) {
if(k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
ll solve(int x)
{
if(x == 1) return 1;
if(mp.count(x)) return mp[x];
mp[x] = quick(2ll, x-1ll);
for(int i = 2;i * i <= x;i ++) {
if(x % i == 0) {
mp[x] = (mp[x] - solve(x / i) + mod) % mod;
if(i != x / i) {
mp[x] = (mp[x] - solve(i) + mod) % mod;
}
}
}
mp[x] = (mp[x] - 1 + mod) % mod;
return mp[x];
}
int main()
{
int x, y;
scanf("%d%d",&x,&y);
if(y % x) {
puts("0");
} else {
y /= x;
printf("%lld\n", solve(y));
}
return 0;
}
2.莫比乌斯函数。
因为
g(t)=∑d|tf(td),且g(t)=2t−1,所以f(t)=∑d|tu(d)g(td)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
int u(int n)
{
if(n == 1) return 1;
int res = 1;
for(int i = 2;i * i <= n;i ++) {
if(n % i == 0) {
res *= -1;
int k = 0;
while(n % i == 0) {
k ++;
n /= i;
if(k > 1) {
return 0;
}
}
}
}
if(n > 1) res *= -1;
return res;
}
ll qmod(ll a, ll k) // a^k
{
ll res = 1;
while(k) {
if(k & 1) res = res * a % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
ll gao(ll x)
{
ll res = 0;
for(int i = 1;i * i <= x;i ++) {
if(x % i == 0) {
res = (res + qmod(2ll, x/i-1ll) * u(i)) % mod;
if(i != x / i) {
res = (res + qmod(2ll, i - 1ll) * u(x / i)) % mod;
}
}
} return res;
}
int main()
{
int x, y;
scanf("%d%d",&x,&y);
if(y % x) {
return puts("0"), 0;
} else {
return printf("%lld\n",(gao(y/x)%mod+mod)%mod), 0;
}
}
————————————————————————————————————————————
————————————————————————————————————————————
E题意:没坑点,自己读下即可。
题解:可以求出连续的从 i 开始 abab… 数量 ai 。
求出问号前缀和 pre[i] 。
然后就变成dp了。
dp[i+1]=max(dp[i+1],dp[i])
dp[i+m]=max(dp[i+m],pair(dp[i]+1,dp[i]+pre[m]−pre[i]))
答案就是
dp[n].second
。
max的定义是数量最大消耗问号最小(注意重载)。
#include <bits/stdc++.h>
using namespace std;
const int N = 1E5 + 7;
struct node
{
int c, w;
node():c(0),w(0){}
node(int a,int b):c(a),w(b){}
bool operator < (const node & x) const {
return c < x.c || c == x.c && w > x.w;
}
}dp[N];
int a[N], b[N], pre[N];
char s[N];
int sum(int l, int r)
{
return pre[r] - pre[l-1];
}
int main()
{
int n, m;
scanf("%d%s%d",&n,s+1,&m);
for(int i = n;i >= 1;i --) {
if(s[i] == 'a') {
a[i] = b[i+1] + 1;
b[i] = 0;
} else if(s[i] == 'b') {
b[i] = a[i+1] + 1;
a[i] = 0;
} else {
a[i] = b[i+1] + 1;
b[i] = a[i+1] + 1;
}
}
for(int i = 1;i <= n;i ++) pre[i] = pre[i-1] + (s[i] == '?');
for(int i = 0;i < n;i ++) {
dp[i+1] = max(dp[i+1], dp[i]);
if(i + m <= n && a[i+1] >= m) {
dp[i+m] = max(dp[i+m], node(dp[i].c+1, dp[i].w+sum(i+1,i+m)));
}
}
printf("%d\n",dp[n].w);
return 0;
}