题意 : 对于一个数 n n n , 判断 n n n能否转换成 n = 2 k 1 + 2 k 2 + . . . + 2 k x + a ! + b ! + . . . c ! n=2^{k_1}+2^{k_2}+...+2^{k_x}+a!+b!+...c! n=2k1+2k2+...+2kx+a!+b!+...c! , 也就是转换成 2 2 2的次方加上一些数阶乘的和
题解 :
#include
#include
#include
#include
#include
#define int long long
#define maxn
using namespace std;
int T,jie[100],n,ans;
vector<int> v;
map<int,int> dp;
int get1(int num){
int temp,cnt=0;
while(num!=0){
temp=num%2;
num=num/2;
if(temp==1) cnt++;
}
return cnt;
}
signed main(){
jie[1]=1;
for(int i=2;i<=15;i++) jie[i]=jie[i-1]*i;
v.push_back(0);
for(int i=3;i<=15;i++){
int temp=v.size();
for(int j=0;j<temp;j++){
if(dp[v[j]+jie[i]]==0) dp[v[j]+jie[i]]=dp[v[j]]+1;
else dp[v[j]+jie[i]]=min(dp[v[j]+jie[i]],dp[v[j]]+1);
v.push_back(v[j]+jie[i]);
}
}
sort(v.begin(),v.end());
scanf("%lld",&T);
wxhile(T--){
scanf("%lld",&n);
ans=get1(n);
for(int i=0;i<=v.size();i++){
if(n-v[i]<0) break;
ans=min(ans,get1(n-v[i])+dp[v[i]]);
}
printf("%lld\n",ans);
}
return 0;
}
题意 : 给定一个树 , 让我们对树的节点进行赋值 , 如果一个节点的值等于它所连接的所有节点的值的总和 , 那么这个节点是一个好节点 , 现在求让好节点的个数最大化的同时让所有的节点的值最小化
题解 :
最小化 , 所以不是好节点的值就为 1 1 1 , 是好节点的值就为它所连接的节点的个数
能看出来这个是一个最小点覆盖问题 , 或者说成最大独立集
设 d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示 i i i节点不是好节点 , d p [ i ] [ 1 ] dp[i][1] dp[i][1]是好节点 , c n t cnt cnt表示这个点的子树及自己好节点的个数 , s u m sum sum就表示这个节点及其子节点的总和为多少
d p [ u ] [ 1 ] . c n t + = d p [ v ] [ 0 ] . c n t d p [ u ] [ 1 ] . s u m + = d p [ v ] [ 0 ] . s u m d p [ u ] [ 0 ] . c n t + = t e m p . c n t d p [ u ] [ 0 ] . s u m + = t e m p . s u m dp[u][1].cnt+=dp[v][0].cnt\\ dp[u][1].sum+=dp[v][0].sum\\ dp[u][0].cnt+=temp.cnt\\ dp[u][0].sum+=temp.sum dp[u][1].cnt+=dp[v][0].cntdp[u][1].sum+=dp[v][0].sumdp[u][0].cnt+=temp.cntdp[u][0].sum+=temp.sum
其中 t e m p temp temp是从子节点的哪一个转移 , 要个数最大化值最小化
#include
#include
#include
#define maxn 300000
using namespace std;
int n,cnt[maxn],k,head[maxn],val[maxn];
struct node{
int to,next;
}edge[maxn<<1];
void add(int u,int v){
edge[++k]=(node) {v,head[u]}; head[u]=k; cnt[u]++;
edge[++k]=(node) {u,head[v]}; head[v]=k; cnt[v]++;
}
struct Node{
int cnt,sum;
friend bool operator == (Node a,Node b){
if(a.cnt==b.cnt && a.sum==b.sum) return true;
return false;
}
}dp[maxn][2];
Node getmax(Node a,Node b){
if(a.cnt>b.cnt) return a;
if(a.cnt==b.cnt && a.sum<b.sum) return a;
return b;
}
void dfs(int u,int fa){
dp[u][0]=(Node){0,1}; //不是好节点
dp[u][1]=(Node){1,cnt[u]}; //是好节点
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==fa) continue;
dfs(v,u);
dp[u][1].cnt+=dp[v][0].cnt;
dp[u][1].sum+=dp[v][0].sum;
Node temp=getmax(dp[v][0],dp[v][1]);
dp[u][0].cnt+=temp.cnt;
dp[u][0].sum+=temp.sum;
}
}
void print(int u,int fa,bool flag){
val[u]=flag?cnt[u]:1;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if(v==fa) continue;
print(v,u,flag?0:getmax(dp[v][0],dp[v][1])==dp[v][1]);
}
}
int main(){
scanf("%d",&n);
for(int i=1,u,v;i<n;i++) scanf("%d %d",&u,&v),add(u,v);
if(n==2) printf("2 2\n1 1\n"),exit(0);
dfs(1,1);
Node temp=getmax(dp[1][0],dp[1][1]);
print(1,1,temp==dp[1][1]);
printf("%d %d\n",temp.cnt,temp.sum);
for(int i=1;i<=n;i++) printf("%d ",val[i]);
return 0;
}
题意 : 求 i j i^j ij不同的个数 , i , j ∈ [ 1 , 1 0 6 ] i,j\in[1,10^6] i,j∈[1,106]
题解 :
第一行全部都是 1 1 1
从第二行开始 , 考虑怎么样才会重复 , 假设现在是 k k k行 , 那么 k m k^m km行会因为第 k k k行而重复 , 例如 2 4 = 4 2 = 8 1 2^4=4^2=8^1 24=42=81 , 然后我们把这个 2 2 2替换成一个符号 a 4 = b 2 = c . . . a^4=b^2=c... a4=b2=c...
for(int i=1;i<=n;i++)
for(int j=1;j*i<=n;j++)
然后需要知道上面的这个循环的复杂度是比较小的 , 差不多 n l o g nlog nlog级别的
然后我们用类似于欧拉筛的方法来计算 , a a a的倍数全部都在 a a a这个地方计算了 , 之后再到那个地方我们就不再进行计算了 , 代码中的预处理其实可以这样写 , 只是会超时超空间 , 可以先这样理解
set<long long> st;
for(int i=1;i<=20;i++){
for(int j=1;j<=m;j++) st.insert(i*j);
s[i]=st.size();
}
也就是计算如果有 b b b个 a a a的倍数在 [ 1 , n ] [1,n] [1,n]的范围内 , 答案是多少 , 又由于 2 20 = 1 , 048 , 576 2^{20}=1,048,576 220=1,048,576 , 所以枚举 20 20 20个就可以了
#include
#include
#define int long long
using namespace std;
int n,m,s[21],cnt;
bool book[20000001];
signed main(){
scanf("%lld %lld",&n,&m);
for(int i=1;i<=20;i++){
for(int j=1;j<=m;j++) cnt+=!book[i*j],book[i*j]=true;
s[i]=cnt;
}
int ans=1;
memset(book,0,sizeof book);
for(int i=2;i<=n;i++){
if(book[i]) continue;
int c=0;
for(int j=i;j<=n;j=j*i) book[j]=1,c++;
ans+=s[c];
}
printf("%lld\n",ans);
return 0;
}