开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第21天,点击查看活动详情
D - Count GCD 容斥
b[i]一定要是a[i]的倍数,a[i-1]也一定要是a[i]的倍数,而且,这样才会保证最大公约数是a[i]而不是a[i]的倍数,上面那个式子也就是要求1~m/a[i]中有多少是与a[i-1]/a[i]互质的,这个用容斥原理来算就可以了,加一个记忆化就能过了,因为a[i]是递减的,a[i-1]/a[i]的值其实很少
算法数学笔记(1) 容斥原理 - 知乎 (zhihu.com)
CodeTON Round 3 (Div. 1 + Div. 2) D (数学 容斥) - 知乎 (zhihu.com)
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int mod=998244353;
const int inf=1e18;
const int N = 4e5+100;
const double eps=1e-8;
int qpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
int getinv(int a){return qpow(a,mod-2LL);}
vector<int>prime;
void pr(int n)
{
prime.clear();
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
prime.push_back(i);
while(n%i==0) n/=i;
}
}
if(n>1) prime.push_back(n);
}
int t,n,m,a[N],num,sum;
void dfs(int pos,int mul,int len)
{
if(pos==prime.size())
{
if(len)
{
if(len&1) sum+=num/mul;
else sum-=num/mul;
}
return;
}
dfs(pos+1,mul,len);
dfs(pos+1,mul*prime[pos],len+1);
}
map<pair<int,int>,int>mp;
int que(int L,int k)
{
if(mp.count({L,k})) return mp[{L,k}];
pr(k);
//cout<<"L="<<L<<" k="<<k<<" siz="<<prime.size()<<endl;
num=L,sum=0;
dfs(0,1,0);
return mp[{L,k}]=(L-sum);
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
cin>>t;
mp.clear();
while(t--)
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
int ans=1;
for(int i=2;i<=n;i++)
{
if(a[i-1]%a[i]!=0){ans=0;break;}
ans=ans*que(m/a[i],a[i-1]/a[i])%mod;
//cout<<ans<<" "<<i<<endl;
}
cout<<ans<<endl;
}
system("pause");
return 0;
}
D-点分治分点_牛客练习赛105 (nowcoder.com)
根据边权排序后一条一条的加边,如果这个点是可以连到s的就是扩展这个点,以这个点扩展的所有点价值都是当前边的w,这一定是最优的,因为是按边权从大到小排的序
牛客练习赛105【出题人题解】 - 知乎 (zhihu.com)
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int mod=998244353;
const int inf=1e18;
const int N = 4e5+100;
const double eps=1e-10;
int qpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
bool integer(double s)
{
if(abs(round(s)-s)<eps) return 1;
return 0;
}
int getinv(int a){return qpow(a,mod-2LL);}
int head[N],cnt;
struct Edge
{
int from,to,w,next;
bool operator<(const Edge& other) const
{
return w>other.w;
}
}e[N],E[N];
void addedge(int from,int to,int w)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].w=w;
head[from]=cnt;
}
int n,m,s,ans[N],vis[N];
void dfs(int u,int w)
{
ans[u]=w;vis[u]=1;
cout<<u<<" "<<w<<endl;
for(int i=head[u];i;i=e[i].next)
{
int j=e[i].to;
if(vis[j]) continue;
dfs(j,w);
}
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
cin>>n>>m>>s;
vis[s]=1;
for(int i=1;i<=m;i++) cin>>E[i].from>>E[i].to>>E[i].w;
sort(E+1,E+m+1);
for(int i=1;i<=n;i++) ans[i]=-1;
for(int i=1;i<=m;i++)
{
auto &[u,v,w,next]=E[i];
addedge(u,v,w);
if(vis[u]==1&&vis[v]==0) dfs(v,w);
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
system("pause");
return 0;
}
1516C - Baby Ehab Partitions Again dp
可以发现如果一开始是可以分成两个子数组的话,最多只要删一个就可以了,那么如何去验证当前数组或者删了一个元素后的数组是否可以呢,背包就可以,但是注意转移的时候只能通过合法的容量来转移,,,
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int mod=998244353;
const int inf=1e18;
const int N = 4e5+100;
const double eps=1e-10;
int qpow(int a,int b)
{
int res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int sgn(double x)
{
if(fabs(x)<eps) return 0;
else if(x<0) return -1;
else return 1;
}
bool integer(double s)
{
if(abs(round(s)-s)<eps) return 1;
return 0;
}
int getinv(int a){return qpow(a,mod-2LL);}
int n,a[105],f[N];
signed main()
{
//ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
cin>>n;
int sum=0;
for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i];
for(int i=1;i<=sum;i++) f[i]=-1;
if(sum&1)
{
cout<<0<<endl;
system("pause");
return 0;
}
f[0]=0;
for(int i=1;i<=n;i++)
for(int j=sum;j>=a[i];j--)
if(f[j-a[i]]!=-1) f[j]=max(f[j],f[j-a[i]]+a[i]);//不合法是不可以的
if(f[sum/2]==-1)
{
cout<<0<<endl;
system("pause");
return 0;
}
int ma=0;
for(int i=1;i<=n;i++)
{
if(((sum-a[i])&1))
{
cout<<"1\n"<<i<<endl;
system("pause");
return 0;
}
int res=sum-a[i];
for(int j=1;j<=sum;j++) f[j]=-1;
for(int k=1;k<=n;k++)
{
if(i==k) continue;
for(int j=res;j>=a[k];j--)
if(f[j-a[k]]!=-1) f[j]=max(f[j],f[j-a[k]]+a[k]);
//注意下标要是k了
}
//cout<<f[res/2]<<" "<<i<<" "<<sum<<endl;
if(f[res/2]==-1)
{
cout<<"1\n"<<i<<endl;
system("pause");
return 0;
}
}
//cout<<"1\n1\n"<<endl;
system("pause");
return 0;
}