需要一点数学思维的一套题,可惜我并没有,于是掉大分
看完题解之后觉得解法相当巧妙,决定写一写
A. Odd Set
题目地址
一句话题意
给定2n个数,问是否存在一种将它们划分为n个pair(a,b)的方法,使得每个pair的和为奇数
n≤100
解
显然一个pair的和为奇数当且仅当它由一个奇数和一个偶数组成
判断是否有奇数个数是否为n即可
代码
略
B. Plus and Multiply
题目地址
一句话题意
给定一个集合S满足
- 1∈S
- 如果x∈S,那么ax∈S,x+b∈S
给定T组n,a,b,求n∈S?
T≤105
1≤n,a,b≤109
解法
假设b=1
n∈S当且仅当存在m∈S使得n≡m(modb)且m<n
显然,要构造出一个新的m mod b,只能采取×a操作,因此m必然是a的幂
判断是否存在ak<n满足n≡ak(modb)即可
特判b=1的情况,显然答案恒为Yes
复杂度O(logn)
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include <iostream> #include <cmath> #include <cstdlib> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; typedef long long ll;
template<typename T>void read(T &t) { t=0;int f=0;char c=getchar(); while(!isdigit(c)){f|=(c=='-');c=getchar();} while(isdigit(c)){t=t*10+c-'0';c=getchar();} if(f)t=-t; }
int T; ll n,a,b;
void Work() { read(n),read(a),read(b); if(b==1) printf("Yes\n"); else if(a==1) { if(n%b==1) printf("Yes\n"); else printf("No\n"); } else { ll k=n%b; for(ll cur=1;cur<=n;cur*=a) { if(cur%b==k) { printf("Yes\n"); return; } } printf("No\n"); } }
int main() { read(T); while(T--) { Work(); } return 0; }
|
C. Strange Function
题目地址
一句话题意
f(n)表示最小的不是n的因数的正整数
计算∑i=1nf(i) mod (109+7)
t(t≤104)组数据
n≤1016
解法
注意到f(n)=i的含义是lcm(1,2,…,i−1)≤n,f(n)的值很小(小于100),因此可以枚举f(i)。
满足f(k)=i的k的数量是⌊lcm(1,2,…,i−1)n⌋−⌊lcm(1,2,…,i)n⌋,亦即k可以被1,2,…,i−1整除而不能被i整除
于是答案即为∑i>1⌊lcm(1,2,…,i−1)n⌋−⌊lcm(1,2,…,i)n⌋
上式还可以表示为∑i≥1⌊lcm(1,2,…,i)n⌋+n
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include <iostream> #include <cmath> #include <cstdlib> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; typedef long long ll;
template<typename T>void read(T &t) { t=0;int f=0;char c=getchar(); while(!isdigit(c)){f|=(c=='-');c=getchar();} while(isdigit(c)){t=t*10+c-'0';c=getchar();} if(f)t=-t; }
const ll mod=1000000007; int T; ll n;
ll Gcd(ll a,ll b) { return b?Gcd(b,a%b):a; }
inline ll Lcm(ll a,ll b) { return a/Gcd(a,b)*b; }
void Work() { read(n); ll lcm=1,ans=0; for(ll i=1;lcm<=n;++i) { lcm=Lcm(lcm,i); (ans+=n/lcm)%=mod; } printf("%lld\n",(ans+n)%mod); }
int main() { read(T); while(T--) { Work(); } return 0; }
|
Tips!
对于值较小的函数的和,可以枚举函数的值、计算值对应变量的个数来将复杂度转移到函数值上
D. Priority Queue
题目地址
一句话题意
对于一个对小根堆进行操作的序列S,其中各元素的形式为+ x
或-
,分别表示入堆和出堆。设f(S)表示依照序列S对小根堆进行操作后,堆中所有元素的和
给定一个序列A,求∑f(B)mod998244353,其中B是A的子序列
n≤500
解法
我们可以计算堆中元素x的贡献
假设我们已经在第I个操作中加入了x,设为X,那么X有贡献的子序列B满足:
- 包含第I个操作
- 设s表示当前堆中小于等于x的元素个数,不管在第I个操作后遇到多少个
-
操作,s必须大于0(除了序列执行结束后)
可以得到以下DP:
设f(i,j)表示满足完成操作后s=j的A[1…i]的子序列个数
转移:
- f(i−1,j)→f(i,j),不包含第i个操作,i=I
- f(i−1,j)→f(i,max(j−1,0)),包含第i个操作,i<I且该操作为
-
- f(i−1,j)→f(i,j−1),包含第i个操作,i>I且该操作为
-
,此时j不可以为0
- f(i−1,j)→f(i,j),包含第i个操作且该操作为
+ x
,其中x>X
- f(i−1,j)→f(i,j+1),包含第i个操作且该操作为
+ x
,其中x<X;或x=X且i>I
X对答案的贡献为X×∑i≥0f(n,i)
复杂度O(n3)
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include <iostream> #include <cmath> #include <cstdlib> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; typedef long long ll;
template<typename T>void read(T &t) { t=0;int f=0;char c=getchar(); while(!isdigit(c)){f|=(c=='-');c=getchar();} while(isdigit(c)){t=t*10+c-'0';c=getchar();} if(f)t=-t; }
const ll mod=998244353; const int maxn=500+5; int n; int a[maxn]; ll dp[maxn][maxn];
int main() { read(n); for(int i=1;i<=n;++i) { char s[10]; gets(s); if(s[0]=='+')sscanf(s+1,"%d",&a[i]); } ll ans=0; for(int t=1;t<=n;++t) { if(a[t]==0) continue; memset(dp,0,sizeof(dp)); dp[0][0]=1; for(int i=1;i<=n;++i) for(int j=0;j<=i;++j) { if(a[i]==0) { if(i<=t || j>0) (dp[i][max(j-1,0)]+=dp[i-1][j])%=mod; } else { if(a[i]<a[t] || a[i]==a[t] && i<t) (dp[i][j+1]+=dp[i-1][j])%=mod; else (dp[i][j]+=dp[i-1][j])%=mod; } if(i!=t) (dp[i][j]+=dp[i-1][j])%=mod; } for(int i=0;i<=n;++i) (ans+=dp[n][i]*a[t]%mod)%=mod; } printf("%lld",ans); return 0; }
|
Tips!
计算贡献的典型例子
E. Abnormal Permutation Pairs
Easy
Hard
题目与多项式有关,需要用到FFT,但是这个科技树暂时灭掉了,以后有机会的话来填一下