OI 笑传 #16

指差す先はインナーワールド

1 ABC423F

终于会了不用二项式反演的做法。

我们把这种东西叫什么好呢?预处理容斥系数?

首先这题是不能一般容斥的,因为我们求解的不是并集,而是独立集。

哎哎独立集是什么东西,就是我随便的一句定义不是图论上的那个独立集。

这里的并集的意思是:至少爆发 \(M\) 中蝉爆发的年份数量,此时我们就是有这种常见的容斥式子:

\[ans= \sum_{i=m}^{n} \left( \sum_{S'\in U,|S'|=i}\left \lfloor \frac{Y}{\operatorname{lcm}_{x\in S'} x}\right \rfloor \times (-1)^{i-m} \right) \]

另外注意到原题 \(m=0\) 时就是这种式子。很有道理啊。

但是我们要求正好有 \(M\)。。

我们记 \(sum_i=\sum_{S'\in U,|S'|=i}\left \lfloor \frac{Y}{\operatorname{lcm}_{x\in S'} x}\right \rfloor \times (-1)^{i-m}\)

此时会有算重(算多)的部分,也就是对于所有包含 \(i+1\) 个年份的集合,我们计算出来它在容斥中的系数。

怎么算呢,我们设系数 \(cnt_i\) 表示大小为 \(i\) 的集合的系数,于是对于所有大小为 \(i\) 的集合,所有大小为 \(j,j<i\) 的集合的系数为 \(cnt_j\),那么对于一种蝉,他会重复被算 \(\dbinom{i}{j}\) 次,为了把这些贡献抹平,我们要让 \(cnt_i=- \left( \dbinom{i}{j}\times cnt_j \right )\)

对所有的 \(m\le j <i\),求和即得系数 \(cnt_i\)。对于所有的 \(m< i \le n\) 应用此方法可得其系数,特殊的,\(cnt_m=1\)

得到系数之后,即可得:

\[ans=\sum_{i=m}^{n} cnt_i \times sum_i \]

没见过的容斥思想。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=30;
ll C[N][N];
bool ofl(ll a,ll b){
  __int128 aa,bb;
  aa=a;bb=b;
  if(aa*bb>=LLONG_MAX)return 1;
  else return 0;
}
ll arr[N];
ll sum[N];
ll d[N];
int main(){
  
  C[0][0]=1;
  for(int i=1;i<=25;i++){
    C[i][0]=1;
    for(int j=1;j<=25;j++){
      C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
  }
  int n,m;cin>>n>>m;ll y;cin>>y;
  for(int i=1;i<=n;i++)cin>>arr[i];
  for(int i=0;i<(1<<n);i++){
    ll reg=1,cnt=0;
    for(int j=0;j<n;j++){
      if((i>>j)&1){
        reg=reg/__gcd(reg,arr[j+1]);
        if(ofl(reg,arr[j+1])){reg=LLONG_MAX;break;}
        reg=reg*arr[j+1];
        cnt++;
      }
    }
    if(cnt>=m&&reg!=0){
    	sum[cnt]+=y/reg;	
		}
  }
  d[m]=1;
  ll ans=sum[m];
  for(int i=m+1;i<=n;i++){
    for(int j=m;j<i;j++){
      d[i]=d[i]+C[i][j]*d[j];
    }
    d[i]=d[i]*-1;
    ans+=d[i]*sum[i];
  }
  cout<<ans;
  
  return 0;
}

1.5

组合数的一些证明:

\[\sum_{i=m}^{k}\binom{k}{i}\binom{i}{m}(-1)^{i-m}=[m=k]\ \ \ (k,m \in \mathbb{Z}^+) \]

首先对于 \(\dbinom{k}{i}\dbinom{i}{m}\),考虑其组合性质就是就是从 \(k\) 中选出 \(i\) 个元素,再从 \(i\) 个元素中选出 \(m\) 个元素的方案数。

我们变一下,也就是先从 \(k\) 个元素中选出 \(m\) 个元素,再在 \(k-m\) 个元素中选出剩下的 \(i-m\) 个元素的方案数。

于是我们有:

\[\binom{k}{i}\binom{i}{m} = \binom{k}{m}\binom{k-m}{i-m} \]

于是原式子可以写作:

\[\binom{k}{m}\sum_{i=m}^{k}\binom{k-m}{i-m}(-1)^{i-m} \]

换元,令 \(j=i-m\),于是:

\[\binom{k}{m}\sum_{j=0}^{k-m}\binom{k-m}{j}(-1)^{j} \]

有点熟悉?二项式定理:

\[\binom{k}{m}\sum_{j=0}^{k-m}\binom{k-m}{j}(-1)^{j}1^{k-m-j} \]

\[\binom{k}{m}(1-1)^{k-m} \]

我们若假设 \(0^0=1\),于是原式就得证了。

proofed by sheep32768。

2

题目描述

你有 \(N\) 只奥术巨兽,每只都有一个攻击力 \(A_i\)

你可以选择任意一个非空子序列的巨兽,并按任意顺序出售它们。
每当出售一只巨兽时,该子序列中所有尚未出售的巨兽的攻击力都会增加刚刚出售的那只巨兽的攻击力。

一个子序列的 价值 定义为:
若依次出售该子序列中的巨兽,直到最后一只售出时所能达到的最大攻击力

你的任务是计算所有非空子序列的价值之和,并对 998244353 取模。


数据范围

  • \(1 \leq T \leq 2 \times 10^5\)
  • \(1 \leq N \leq 2 \times 10^5\)
  • \(0 \leq A_i < 998244353\)
  • 所有测试中 \(\sum N \leq 2 \times 10^5\)

最初看题还以为是字串,于是就直接去想分治了,但是再看一遍题才看见是子序列。

但是也不慌,我们依然考虑对每一个数算贡献。

首先手摸下就知道最优策略是从大到小删数,于是先考虑一个有序数列 \(a_1,a_2,\cdots,a_n\),再次进行手摸就可以发现价值为 \(a_1+a_2 \times 2^0+a_3 \times 2^1+\cdots a_n \times 2^{n-1}\)

把系数提出来:\(1,2^0,2^1,2^2,\cdots,2^{n-1}\)

基于此,我们首先把序列排个序,可能会有重复但是没关系,我们设序列 \(a\)\(1\) 开始编号,对于一个元素 \(a_i\)

在前面,我们可以选出来 \(0 \sim i-1\) 个数,对于选 \(0\) 个那么当然在序列里的系数就是 \(1\),选 \(j > 0\) 个时,有 \(\dbinom{i-1}{j}\) 种选法,不论怎么选,\(a_i\) 的系数都是 \(2^{j-1}\)

于是系数和为:

\[\sum_{j=1}^{i-1} \binom{i-1}{j}2^{j-1}+1 \]

怎么场上姜汁了好久都不会化前半部分来着,也是个二项式定理:

\[\frac{\sum_{j=1}^{i-1} \binom{i-1}{j}2^{j}}{2}+1 \]

\[\frac{\sum_{j=1}^{i-1} \binom{i-1}{j}2^{j}1^{i-j-1}}{2}+1 \]

注意 \(j\)\(1\) 开始

\[\frac{(2+1)^{i-1}-1}{2}+1 \]

\[\frac{(2+1)^{i-1}+1}{2} \]

这是考虑前面选择的数量是系数和,由于前面选择的数的数量会影响系数,我们做了这些推导。

还没完,后面可能还有元素呢,但显然后面怎么选无所谓,只要前面选的数确定了就不会影响系数,后面选择的情况一共就是有 \(2^{n-i}\) 种。

于是乘起来即可:

\[a_i \times \frac{(2+1)^{i-1}+1}{2} \times 2^{n-i} \]

这是一个元素的贡献,求个和就是答案。

\[ans=\sum_{i=1}^{n} a_i \times \frac{(2+1)^{i-1}+1}{2} \times 2^{n-i} \]

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=2e5+5;
const int mod=998244353;
ll fac[N];
ll pre[N];
ll inv2;
ll qp(ll a,ll b){
  ll res=1,k=a;
  while(b){
    if(b&1){res=res*k%mod;}
    k=k*k%mod;
    b>>=1;
  }
  return res;
}
ll C(ll n,ll m){
  ll u=fac[n];
  ll d=qp(fac[m]*fac[n-m]%mod,mod-2);
  return u*d%mod;
}
ll arr[N];
void init(){
  return ;
}
void solve(){
  
  int n;cin>>n;
  for(int i=1;i<=n;i++){
    cin>>arr[i];
  }
  sort(arr+1,arr+1+n);
  ll ans=0;
  for(int i=1;i<=n;i++){
    ans=(ans+(qp(3,i-1)%mod+1+mod)%mod*inv2%mod*qp(2,n-i)%mod*arr[i]%mod)%mod;
  }
  cout<<ans<<'\n';
  return ;
}
int main(){
  
  // freopen("monster.in","r",stdin);
  // freopen("monster.out","w",stdout);

  fac[0]=1;
  for(int i=1;i<=2e5;i++){fac[i]=fac[i-1]*i%mod;}
  inv2=qp(2,mod-2);

  int T;cin>>T;
  while(T--){
    init();solve();
  }
  
  return 0;
}

3

给定一个长度为 \(n\) 的整数序列 \(A_1, A_2, \dots, A_n\)
接下来有 \(q\) 次询问,每次询问给出两个整数 \(x, y\)
请你计算满足 \(1 \le i < j \le n\),且 \(A_i = x, A_j = y\) 的有序整数对 \(i, j\) 的个数。

数据范围

  • \(1 \le n, q \le 10^5\)
  • \(1 \le A_i, x, y \le 10^9\)

首先在线肯定不好做,我们离线下来。

具体的,也就是把询问挂在颜色上,每次从后往前处理,记录所有颜色的出现次数。访问到一个有询问的颜色就依次处理。

但是这样有些问题,如果询问的颜色在数组中出现的次数很多,可以退化到 \(O(nq)\)

出现次数和一定,出现多的元素会劣,这里比较熟悉根号分治思想的话一定会去往根号分治想的,不想我就在那里法坐了。

具体的,我们求解答案可以从后往前也可以从前往后。

我们统计出颜色的出现次数,让放入离线询问数组的为那个出现次数较小的元素。

于是就是 \(O(n\sqrt{n})\) 了。证明参考根号分治的方法。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=2e5+1145;
vector<pair<int,int> > lqans[N],rqans[N];
map<int,int> exs;
int arr[N];
ll ans[N];
int ap[N];
int app[N];
map<int,bool> exis;
vector<int> vc;
vector<int>::iterator rbn;
int regis(int x){
  return lower_bound(vc.begin(),rbn,x)-vc.begin()+1;
}
int main(){
  
  // freopen("pii.in","r",stdin);
  // freopen("pii.out","w",stdout);

  int n,q;cin>>n>>q;
  for(int i=1;i<=n;i++){
    cin>>arr[i];
    vc.push_back(arr[i]);
    exis[arr[i]]=1;
  }
  sort(vc.begin(),vc.end());
  auto rb=unique(vc.begin(),vc.end());
  rbn=rb;
  for(int i=1;i<=n;i++){
    int wp=regis(arr[i]);
    arr[i]=wp;
    ap[wp]++;
  }
  for(int i=1;i<=q;i++){
    int x,y;cin>>x>>y;
    if(exis.find(x)==exis.end()||exis.find(y)==exis.end()){ans[i]=0;continue;}
    int a=regis(x);int b=regis(y);
    if(ap[a]>ap[b])lqans[b].push_back(mkp(a,i));
    else rqans[a].push_back(mkp(b,i));
  }
  for(int i=n;i>=1;i--){
    for(pair<int,int> v:rqans[arr[i]]){
      ans[v.second]+=app[v.first];
    }
    app[arr[i]]++; 
  }
  memset(app,0,sizeof app);
  for(int i=1;i<=n;i++){
    app[arr[i]]++;
    for(pair<int,int> v:lqans[arr[i]]){
      ans[v.second]+=app[v.first];
    }
  }
  for(int i=1;i<=q;i++){cout<<ans[i]<<'\n';}
  
  return 0;
}

4 洛谷 P2557

数学题?其实可以 DP 做。

首先对 \(n\) 进行简单的质因数分解,再把每种元素出现次数乘 \(k\) 就是 \(n^k\) 的质因数分解。

接下来给质因数数组排个序,设其为 \(a_i\),设 \(f_i,g_i\),转移是下面:

\(i=1\) 时:

\[f_i=a_i,g_i=a_i \]

\(a_i \ne a_{i-1}\),按顺序有下列转移:

\[f_i=g_{i-1} \times a_i,g_i=g_{i-1}+f_i \]

\(a_i = a_{i-1}\),按顺序有下列转移:

\[f_i=f_{i-1} \times a_i,g_i=g_{i-1}+f_i \]

答案是 \(g_{n}+1\)

推导的话,就是你想象 \(f_i\) 中保存的是以当前质因子结尾的所有因数列表,\(g_i\) 中保存的是全局的因数列表,如是转移即可。

code,要用一个高精度类:

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
struct BigInteger {
	private:
		deque<int> num;
		bool sgn;
		
	public:
		BigInteger operator = (long long init) {
			num.clear();
			if (init) {
				if (init > 0) sgn = true;
				else {
					sgn = false;
					init = -init;
				}
				while (init) {
					num.push_front(init % 10);
					init /= 10;
				}
			} else {
				sgn = true;
				num.push_back(0);
			}
			return *this;
		}
		
		BigInteger operator = (int init) { return (*this = (long long) init); }
		
		BigInteger operator = (const char *s) {
			num.clear();
			assert(*s);
			if (*s == '-') {
				sgn = false;
				assert(*(++s));
			} else sgn = true;
			while (*s) {
				assert(isdigit(*s));
				num.push_back(*(s++) - '0');
			}
			if (num.size() >= 2) assert(num[0]);
			assert(sgn || num[0]);
			return *this;
		}
		
		BigInteger() { *this = 0LL; }
		BigInteger(int init) { *this = init; }
		BigInteger(long long init) { *this = init; } 
		BigInteger(const char *s) { *this = s; }
		BigInteger(string s) { *this = s.c_str(); }
		
		BigInteger operator - () {
			if (num[0] == 0) return *this;
			BigInteger ret = *this;
			ret.sgn = !ret.sgn;
			return ret;
		}
		
		bool operator < (const BigInteger &rhs) const {
			if (sgn != rhs.sgn) return !sgn;
			if (num.size() < rhs.num.size()) return sgn;
			if (num.size() > rhs.num.size()) return !sgn;
			for (int i = 0; i < num.size(); i++)
				if (num[i] != rhs.num[i])
					return (sgn ? (num[i] < rhs.num[i]) : (num[i] > rhs.num[i]));
			return false;
		}
		bool operator < (int rhs) const { return *this < BigInteger(rhs); }
		bool operator < (long long rhs) const { return *this < BigInteger(rhs); }
		bool operator < (const char *rhs) const { return *this < BigInteger(rhs); }
		bool operator < (string rhs) const { return *this < BigInteger(rhs); }
		
		bool operator > (const BigInteger &rhs) const { return rhs < *this; }
		bool operator > (int rhs) const { return *this > BigInteger(rhs); }
		bool operator > (long long rhs) const { return *this > BigInteger(rhs); }
		bool operator > (const char *rhs) const { return *this > BigInteger(rhs); }
		bool operator > (string rhs) const { return *this > BigInteger(rhs); }
		
		bool operator <= (const BigInteger &rhs) const { return !(*this > rhs); }
		bool operator <= (int rhs) const { return *this <= BigInteger(rhs); }
		bool operator <= (long long rhs) const { return *this <= BigInteger(rhs); }
		bool operator <= (const char *rhs) const { return *this <= BigInteger(rhs); }
		bool operator <= (string rhs) const { return *this <= BigInteger(rhs); }
		
		bool operator >= (const BigInteger &rhs) const { return !(*this < rhs); }
		bool operator >= (int rhs) const { return *this >= BigInteger(rhs); }
		bool operator >= (long long rhs) const { return *this >= BigInteger(rhs); }
		bool operator >= (const char *rhs) const { return *this >= BigInteger(rhs); }
		bool operator >= (string rhs) const { return *this >= BigInteger(rhs); }
		
		bool operator == (const BigInteger &rhs) const { return !(*this < rhs) && !(*this > rhs); }
		bool operator == (int rhs) const { return *this == BigInteger(rhs); }
		bool operator == (long long rhs) const { return *this == BigInteger(rhs); }
		bool operator == (const char *rhs) const { return *this == BigInteger(rhs); }
		bool operator == (string rhs) const { return *this == BigInteger(rhs); }
		
		bool operator != (const BigInteger &rhs) const { return !(*this == rhs); }
		bool operator != (int rhs) const { return *this != BigInteger(rhs); }
		bool operator != (long long rhs) const { return *this != BigInteger(rhs); }
		bool operator != (const char *rhs) const { return *this != BigInteger(rhs); }
		bool operator != (string rhs) const { return *this != BigInteger(rhs); }
		
		operator bool() {
			return num[0];
		}
		
		operator string() {
			string ret;
			if (!sgn) ret += "-";
			for (int i = 0; i < num.size(); i++) {
				ret += num[i] + '0';
			}
			return ret;
		}
		
		operator int() {
			int ret = 0;
			for (int i = 0; i < num.size(); i++) ret = ret * 10 + num[i];
			return ret;
		}
		
		operator long long() {
			long long ret = 0;
			for (int i = 0; i < num.size(); i++) ret = ret * 10 + num[i];
			return ret;
		}
		
		friend istream& operator >> (istream &in, BigInteger &lhs) {
			string init;
			in >> init;
			lhs = init;
			return in;
		}
		
		friend ostream& operator << (ostream &out, BigInteger lhs) {
			out << (string) lhs;
			return out;
		}
		
		friend BigInteger operator + (BigInteger, BigInteger);
		friend BigInteger operator - (BigInteger, BigInteger);
		friend BigInteger operator * (BigInteger, BigInteger);
		friend BigInteger operator / (BigInteger, BigInteger);
		friend BigInteger operator % (BigInteger, BigInteger);
		
		friend BigInteger operator + (BigInteger lhs, int rhs) { return lhs + BigInteger(rhs); }
		friend BigInteger operator + (BigInteger lhs, long long rhs) { return lhs + BigInteger(rhs); }
		friend BigInteger operator + (BigInteger lhs, const char *rhs) { return lhs + BigInteger(rhs); }
		friend BigInteger operator + (BigInteger lhs, string rhs) { return lhs + BigInteger(rhs); }
		friend BigInteger operator + (int lhs, BigInteger rhs) { return BigInteger(lhs) + rhs; }
		friend BigInteger operator + (long long lhs, BigInteger rhs) { return BigInteger(lhs) + rhs; }
		friend BigInteger operator + (const char *lhs, BigInteger rhs) { return BigInteger(lhs) + rhs; }
		friend BigInteger operator + (string lhs, BigInteger rhs) { return BigInteger(lhs) + rhs; }
		
		friend BigInteger operator - (BigInteger lhs, int rhs) { return lhs - BigInteger(rhs); }
		friend BigInteger operator - (BigInteger lhs, long long rhs) { return lhs - BigInteger(rhs); }
		friend BigInteger operator - (BigInteger lhs, const char *rhs) { return lhs - BigInteger(rhs); }
		friend BigInteger operator - (BigInteger lhs, string rhs) { return lhs - BigInteger(rhs); }
		friend BigInteger operator - (int lhs, BigInteger rhs) { return BigInteger(lhs) - rhs; }
		friend BigInteger operator - (long long lhs, BigInteger rhs) { return BigInteger(lhs) - rhs; }
		friend BigInteger operator - (const char *lhs, BigInteger rhs) { return BigInteger(lhs) - rhs; }
		friend BigInteger operator - (string lhs, BigInteger rhs) { return BigInteger(lhs) - rhs; }
		
		friend BigInteger operator * (BigInteger lhs, int rhs) { return lhs * BigInteger(rhs); }
		friend BigInteger operator * (BigInteger lhs, long long rhs) { return lhs * BigInteger(rhs); }
		friend BigInteger operator * (BigInteger lhs, const char *rhs) { return lhs * BigInteger(rhs); }
		friend BigInteger operator * (BigInteger lhs, string rhs) { return lhs * BigInteger(rhs); }
		friend BigInteger operator * (int lhs, BigInteger rhs) { return BigInteger(lhs) * rhs; }
		friend BigInteger operator * (long long lhs, BigInteger rhs) { return BigInteger(lhs) * rhs; }
		friend BigInteger operator * (const char *lhs, BigInteger rhs) { return BigInteger(lhs) * rhs; }
		friend BigInteger operator * (string lhs, BigInteger rhs) { return BigInteger(lhs) * rhs; }
		
		friend BigInteger operator / (BigInteger lhs, int rhs) { return lhs / BigInteger(rhs); }
		friend BigInteger operator / (BigInteger lhs, long long rhs) { return lhs / BigInteger(rhs); }
		friend BigInteger operator / (BigInteger lhs, const char *rhs) { return lhs / BigInteger(rhs); }
		friend BigInteger operator / (BigInteger lhs, string rhs) { return lhs / BigInteger(rhs); }
		friend BigInteger operator / (int lhs, BigInteger rhs) { return BigInteger(lhs) / rhs; }
		friend BigInteger operator / (long long lhs, BigInteger rhs) { return BigInteger(lhs) / rhs; }
		friend BigInteger operator / (const char *lhs, BigInteger rhs) { return BigInteger(lhs) / rhs; }
		friend BigInteger operator / (string lhs, BigInteger rhs) { return BigInteger(lhs) / rhs; }
		
		friend BigInteger operator % (BigInteger lhs, int rhs) { return lhs % BigInteger(rhs); }
		friend BigInteger operator % (BigInteger lhs, long long rhs) { return lhs % BigInteger(rhs); }
		friend BigInteger operator % (BigInteger lhs, const char *rhs) { return lhs % BigInteger(rhs); }
		friend BigInteger operator % (BigInteger lhs, string rhs) { return lhs % BigInteger(rhs); }
		friend BigInteger operator % (int lhs, BigInteger rhs) { return BigInteger(lhs) % rhs; }
		friend BigInteger operator % (long long lhs, BigInteger rhs) { return BigInteger(lhs) % rhs; }
		friend BigInteger operator % (const char *lhs, BigInteger rhs) { return BigInteger(lhs) % rhs; }
		friend BigInteger operator % (string lhs, BigInteger rhs) { return BigInteger(lhs) % rhs; }
		
		BigInteger & operator += (BigInteger rhs) {
			*this = *this + rhs;
			return *this;
		}
		BigInteger & operator += (int rhs) {
			*this = *this + BigInteger(rhs);
			return *this;
		}
		BigInteger & operator += (long long rhs) {
			*this = *this + BigInteger(rhs);
			return *this;
		}
		BigInteger & operator += (const char *rhs) {
			*this = *this + BigInteger(rhs);
			return *this;
		}
		BigInteger & operator += (string rhs) {
			*this = *this + BigInteger(rhs);
			return *this;
		}
		
		BigInteger & operator -= (BigInteger rhs) {
			*this = *this - rhs;
			return *this;
		}
		BigInteger & operator -= (int rhs) {
			*this = *this - BigInteger(rhs);
			return *this;
		}
		BigInteger & operator -= (long long rhs) {
			*this = *this - BigInteger(rhs);
			return *this;
		}
		BigInteger & operator -= (const char *rhs) {
			*this = *this - BigInteger(rhs);
			return *this;
		}
		BigInteger & operator -= (string rhs) {
			*this = *this - BigInteger(rhs);
			return *this;
		}
		
		BigInteger & operator *= (BigInteger rhs) {
			*this = *this * BigInteger(rhs);
			return *this;
		}
		BigInteger & operator *= (int rhs) {
			*this = *this * BigInteger(rhs);
			return *this;
		}
		BigInteger & operator *= (long long rhs) {
			*this = *this * BigInteger(rhs);
			return *this;
		}
		BigInteger & operator *= (const char *rhs) {
			*this = *this * BigInteger(rhs);
			return *this;
		}
		BigInteger & operator *= (string rhs) {
			*this = *this * BigInteger(rhs);
			return *this;
		}
		
		BigInteger & operator /= (BigInteger rhs) {
			*this = *this / rhs;
			return *this;
		}
		BigInteger & operator /= (int rhs) {
			*this = *this / BigInteger(rhs);
			return *this;
		}
		BigInteger & operator /= (long long rhs) {
			*this = *this / BigInteger(rhs);
			return *this;
		}
		BigInteger & operator /= (const char *rhs) {
			*this = *this / BigInteger(rhs);
			return *this;
		}
		BigInteger & operator /= (string rhs) {
			*this = *this / BigInteger(rhs);
			return *this;
		}
		
		BigInteger & operator %= (BigInteger rhs) {
			*this = *this % BigInteger(rhs);
			return *this;
		}
		BigInteger & operator %= (int rhs) {
			*this = *this % BigInteger(rhs);
			return *this;
		}
		BigInteger & operator %= (long long rhs) {
			*this = *this % BigInteger(rhs);
			return *this;
		}
		BigInteger & operator %= (const char *rhs) {
			*this = *this % BigInteger(rhs);
			return *this;
		}
		BigInteger & operator %= (string rhs) {
			*this = *this % BigInteger(rhs);
			return *this;
		}
		
		BigInteger & operator ++ () {
			*this += BigInteger(1);
			return *this;
		}
		
		BigInteger operator ++ (int _) {
			BigInteger tmp(*this);
			*this += BigInteger(1);
			return tmp;
		}
		
		BigInteger & operator -- () {
			*this -= BigInteger(1);
			return *this;
		}
		
		BigInteger operator -- (int _) {
			BigInteger tmp(*this);
			*this -= BigInteger(1);
			return tmp;
		}
		
		BigInteger pow(BigInteger n) {
			assert(*this);
			assert(n >= 0);
			if (n == BigInteger(0)) return BigInteger(1);
			BigInteger res = pow(n / BigInteger(2));
			if (n % BigInteger(2)) return res * res * (*this);
			return res * res;
		}
		BigInteger pow(int n) { return pow(BigInteger(n)); }
		BigInteger pow(long long n) { return pow(BigInteger(n)); }
		BigInteger pow(const char *n) { return pow(BigInteger(n)); }
		BigInteger pow(string n) { return pow(BigInteger(n)); }
};

BigInteger operator + (BigInteger lhs, BigInteger rhs) {
	if (lhs.sgn && !rhs.sgn) {
		rhs.sgn = true;
		return lhs - rhs;
	}
	if (!lhs.sgn && rhs.sgn) {
		lhs.sgn = true;
		return rhs - lhs;
	}
	if (lhs.num.size() < rhs.num.size()) swap(lhs, rhs);
	for (int i = 0; i < rhs.num.size(); i++)
		lhs.num[lhs.num.size() - rhs.num.size() + i] += rhs.num[i];
	for (int i = lhs.num.size() - 1; i > 0; i--) {
		lhs.num[i - 1] += lhs.num[i] / 10;
		lhs.num[i] %= 10;
	}
	if (lhs.num[0] >= 10) {
		lhs.num.push_front(lhs.num[0] / 10);
		lhs.num[1] %= 10;
	}
	return lhs;
}

BigInteger operator - (BigInteger lhs, BigInteger rhs) {
	if (lhs.sgn && !rhs.sgn) {
		rhs.sgn = true;
		return lhs + rhs;
	}
	if (!lhs.sgn && rhs.sgn) return lhs + rhs;
	if (!lhs.sgn && !rhs.sgn) {
		lhs.sgn = true;
		rhs.sgn = true;
		return rhs - lhs;
	}
	if (lhs < rhs) return -(rhs - lhs);
	for (int i = lhs.num.size() - rhs.num.size(); i < lhs.num.size(); i++) 
		lhs.num[i] -= rhs.num[rhs.num.size() + i - lhs.num.size()];
	for (int i = lhs.num.size() - 1; i > 0; i--) {
		while (lhs.num[i] < 0) {
			lhs.num[i - 1]--;
			lhs.num[i] += 10;
		}
	}
	while (lhs.num.size() >= 2 && lhs.num[0] == 0) lhs.num.pop_front();
	return lhs;
}

BigInteger operator * (BigInteger lhs, BigInteger rhs) {
	deque<int> mul(lhs.num.size() + rhs.num.size(), 0);
	reverse(lhs.num.begin(), lhs.num.end());
	reverse(rhs.num.begin(), rhs.num.end());
	for (int i = 0; i < lhs.num.size(); i++)
		for (int j = 0; j < rhs.num.size(); j++)
			mul[i + j] += lhs.num[i] * rhs.num[j];
	for (int i = 0; i < mul.size() - 1; i++) {
		mul[i + 1] += mul[i] / 10;
		mul[i] %= 10;
	}
	if (mul[mul.size() - 1]) {
		mul.push_back(mul[mul.size() - 1] / 10);
		mul[mul.size() - 2] %= 10;
	}
    while (mul.size() >= 2 && mul[mul.size() - 1] == 0) mul.pop_back();
	reverse(mul.begin(), mul.end());
	lhs.sgn = (lhs.sgn ^ rhs.sgn ^ 1);
	lhs.num = mul;
	return lhs;
}

BigInteger operator / (BigInteger lhs, BigInteger rhs) {
	assert(rhs);
	BigInteger ret, cnt, div;
	bool sgn = (lhs.sgn ^ rhs.sgn ^ 1);
	rhs.sgn = true;
	div.num.clear();
	for (int i = 0; i < lhs.num.size(); i++) {
		while (!div.num.empty() && div.num[0] == 0) div.num.pop_front();
		div.num.push_back(lhs.num[i]);
		cnt = 0;
		while (div > rhs) {
			div -= rhs;
			cnt++;
		}
		if (div == rhs) {
			div = 0;
			cnt++;
		}
		ret = ret * BigInteger(10) + cnt;
	}
	ret.sgn = sgn;
	return ret; 
}

BigInteger operator % (BigInteger lhs, BigInteger rhs) {
	return lhs - lhs / rhs * rhs;
}

typedef BigInteger BigInt;
vector<int> vm;
vector<int> pl;
int ccnt[65590];
ll f[65590],g[65590];
int main(){ 
  
  int n,k;cin>>n>>k;
  int n2=n;
  for(int i=2;i<=(5000);i++){
    bool isok=1;
    for(int j=2;j*j<=i;j++){
      if(i%j==0){isok=0;break;}
    }
    if(isok==1)pl.push_back(i);
  }
  int cnt=0;
  while(cnt<pl.size()&&n>=1){
    while(n%pl[cnt]==0){
      ccnt[pl[cnt]]++;
      n/=pl[cnt];
    }
    cnt++;
  }
  for(int i=1;i<=65590;i++){
    for(int j=1;j<=ccnt[i]*k;j++){
      vm.push_back(i);
    }
  }
  // for(int v:vm)cout<<v<<' ';
  // cout<<'\n';
  ll anss=0;
  f[0]=vm[0];g[0]=vm[0];
  for(int i=1;i<vm.size();i++){
    if(vm[i]!=vm[i-1]){
      f[i]=g[i-1]*vm[i];
      g[i]=g[i-1]+f[i];
    }
    else{
      f[i]=f[i-1]*vm[i];
      g[i]=g[i-1]+f[i];
    }
  }
  cout<<anss+g[vm.size()-1]+1<<'\n';

  int res=1;
  for(int i=1;i<=k;i++){
    res=res*n2;
  }
  n=res;
  ll ans=0;
  for(int i=1;i*i<=n;i++){
    if(i*i==n){
      ans+=i;
      break;
    }
    if(n%i==0)ans+=i+n/i;
  }
  cout<<ans<<'\n';
  
  return 0;
}

5. Luogu P10418

上来就写了一个 DP,结果当然 TLE 了。

DP code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=2e5+5;
struct ed{
  ll v,w;
};
vector<ed> e[N];
ll dp[N][6];
ll ans=0;
void dfs(int u,int fa){
  ll maxw=0;
  for(ed to:e[u]){
    ll v=to.v;ll w=to.w;
    if(v==fa)continue;
    dfs(v,u);
    maxw=max(maxw,w);
  }
  dp[u][1]=maxw;
  for(ed t1:e[u]){
    if(t1.v==fa)continue;
    for(ed t2:e[u]){
      if(t1.v==t2.v||t2.v==fa)continue;
      dp[u][2]=max(dp[u][2],t1.w+t2.w);
      dp[u][3]=max(dp[u][3],t1.w+t2.w+max(dp[t1.v][1],dp[t2.v][1]));
    }
    dp[u][2]=max(dp[u][2],dp[t1.v][1]+t1.w);
    dp[u][3]=max(dp[u][3],t1.w+dp[t1.v][2]);
  }
  ans=max(ans,dp[u][3]);
  return ;
}
int main(){
  
  int n;cin>>n;
  for(int i=1;i<n;i++){
    int to,w;cin>>to>>w;
    e[to].push_back(ed{i+1,w});
    e[i+1].push_back(ed{to,w});
  }
  dfs(1,0);
  cout<<ans;

  return 0;
}

注意到转移的时候重复找了多次最大值,于是预处理一下就可过了。

练习马力。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=2e5+5;
struct ed{
  ll v,w;
};
vector<ed> e[N];
ll dp[N][6];
ll ans=0;
bool cmp(ll u,ll v){return u>v;}
bool cmp1(pair<int,ll> x,pair<int,ll> y){
  return x.second>y.second;
}
void dfs(int u,int fa){
  ll maxw=0;
  vector<ll> wk;
  vector<pair<int,ll> >ps;
  for(ed to:e[u]){
    ll v=to.v;ll w=to.w;
    if(v==fa)continue;
    dfs(v,u);
    wk.push_back(w);
    dp[u][2]=max(dp[u][2],dp[v][1]+w);
    dp[u][3]=max(dp[u][3],dp[v][2]+w);
    ps.push_back(mkp(v,w+dp[v][1]));
  }
  sort(wk.begin(),wk.end(),cmp);
  sort(ps.begin(),ps.end(),cmp1);
  if(wk.size()==0)return ;
  dp[u][1]=wk[0];
  if(wk.size()>2){
    dp[u][2]=max(dp[u][2],wk[0]+wk[1]);
  }
  if(wk.size()>=3){
    dp[u][3]=max(dp[u][3],wk[0]+wk[1]+wk[2]);
  }
  if(ps.size()<=1)return ;
  for(ed to:e[u]){
    ll v=to.v;ll w=to.w;
    if(v==ps[0].first)dp[u][3]=max(dp[u][3],w+ps[1].second);
    else dp[u][3]=max(dp[u][3],w+ps[0].second);
  }
  ans=max(ans,dp[u][3]);
  return ;
}
signed main(){
  
  int n;cin>>n;
  for(int i=1;i<n;i++){
    ll to,w;cin>>to>>w;
    e[to].push_back(ed{i+1,w});
    e[i+1].push_back(ed{to,w});
  }
  dfs(1,0);
  cout<<ans;

  return 0;
}

6. Luogu P10477

我们可以根据操作和约束非常自然的构造出两棵树,于是接下来就是树哈希模板。

练习马力。

code

Show me the code
#define psb push_back
#define mkp make_pair
#define ls p<<1
#define rs (p<<1)+1
#define rep(i,a,b) for( int i=(a); i<=(b); ++i)
#define per(i,a,b) for( int i=(a); i>=(b); --i)
#define rd read()
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll read(){
  ll x=0,f=1;
  char c=getchar();
  while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
  while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
  return x*f;
}
const int N=4000;
int f1[N],f2[N];
int cnt1,cnt2;
int r1,r2;
vector<int> e1[N],e2[N];
int m;
map<vector<int>,int> mp;
int calc1(int x,int pr){
  vector<int>a={-1};
  for(int y:e1[x])
    if(y!=pr)a.push_back(calc1(y,x));
  sort(a.begin(),a.end());
  if(!mp[a])mp[a]=++m;
  return mp[a];
}
int calc2(int x,int pr){
  vector<int>a={-1};
  for(int y:e2[x])
    if(y!=pr)a.push_back(calc2(y,x));
  sort(a.begin(),a.end());
  if(!mp[a])mp[a]=++m;
  return mp[a];
}
int main(){
  
  int n;cin>>n;
  while(n--){
    string s1,s2;
    cin>>s1>>s2;
    cnt1=cnt2=1;
    r1=r2=1;
    m=0;
    mp.clear();
    memset(e1,0,sizeof e1);
    memset(e2,0,sizeof e2);
    memset(f1,0,sizeof f1);
    memset(f2,0,sizeof f2);
    for(char a:s1){
      if(a=='0'){
        cnt1++;
        f1[cnt1]=r1;
        r1=cnt1;
      }
      if(a=='1')r1=f1[r1];
    }
    for(char a:s2){
      if(a=='0'){
        cnt2++;
        f2[cnt2]=r2;
        r2=cnt2;
      }
      if(a=='1')r2=f2[r2];
    }
    for(int i=1;i<=cnt1;i++){
      if(f1[i]!=0){
        e1[i].push_back(f1[i]);
        e1[f1[i]].push_back(i);
      }
    }
    for(int i=1;i<=cnt2;i++){
      if(f2[i]!=0){
        e2[i].push_back(f2[i]);
        e2[f2[i]].push_back(i);
      }
    }
    int ss1=calc1(1,0);
    int ss2=calc2(1,0);
    if(ss1==ss2){cout<<"same"<<'\n';}
    else {cout<<"different"<<'\n';}
  }
  
  return 0;
}
posted @ 2025-10-05 17:24  hm2ns  阅读(13)  评论(0)    收藏  举报