T1 子集和

解题思路

大概是一个退背包的大白板,然而我考场上想复杂了,竟然还用到了组合数。

但是大概意思是一样的,有数的最小值一定是一个在 \(a\) 数组中存在的数字。

那么我们想办法除去它对应的贡献,可以一个一个退,也可以组合数一下一起退。。。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigend long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e4+10;
int n,cnt,m,top,s[N],t[N],ans[N],all[N];
inline int C(int x,int y)
{
__int128 temp=1; int p=1;
for(int i=y+1;i<=x;i++){temp*=i; while(p<=x-y&&temp%p==0) temp/=p,p++;}
return (int)temp;
}
#undef int
int main()
{
#define int long long
freopen("subset.in","r",stdin); freopen("subset.out","w",stdout);
n=read(); m=read();
for(int i=0;i<=m;i++) s[i]=read();
while(cnt<n)
{
int num,tot;
for(int i=1;i<=m;i++)
if(s[i]){num=i;tot=s[i];break;}
for(int i=1;i<=tot;i++) ans[++cnt]=num;
for(int i=1;i<=tot;i++) all[i]=C(tot,i),s[i*num]-=all[i];
for(int j=num+1;j<=m;j++)
{
if(!s[j]) continue;
for(int k=1;k<=tot;k++)
s[j+num*k]-=all[k]*s[j];
}
}
sort(ans+1,ans+n+1);
for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
return 0;
}

T2 异或

解题思路

官方题解是枚举 \(k\) 的位置,然后 Tire 树计算答案,然而。。。

我的做法是对于不同的二进制位枚举 \(j\) 的位置,并计算贡献。

假设当前处理到的二进制位是 \(p\) 所有二进制位最高是 \(m\) 。

那么一对 \((i,k)\) 对于 \(j\) 有贡献,当且仅当 \(a_i,a_k\) 的 \([p+1,m]\) 这几个二进制位相同,并且如果 \(a_j\) 的这一位是 0 \(a_i\) 的这一位也是 0 \(a_k\) 的这一位也是 1 ,或者\(a_j\) 的这一位是 1 \(a_i\) 的这一位也是 1 \(a_k\) 的这一位也是 0 。

那么我们可以对于 \([p+1,m]\) 这几位出现过的数字以及 \(p\) 位上的数字开一个桶,然后直接计算贡献。

然而这样需要优化,我们可以计算每一次移动的变化值,然后记录第 \(j\) 个数字的第 \(p\) 位是 1 或者 0 的答案直接计入贡献。

具体实现开一个前缀的桶一个后缀的桶,然后可能需要离散化一下,这样会被卡常。。。

发现有些比较高的位是没有必要离散化的我们直接算就可以了,于是卡常成功!!

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigend long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=1e7+10,M=5e5+10;
int n,m,ans,cnt,lsh[N],s[M],p[M],pre[2][N],suf[2][N];
inline void solve(register int pos)
{
register int U=((1ll<<m-pos)-1)<<pos+1,bas[2]={0,0};
if((1ll<<m-pos)-1<=10000000)
{
for(register int i=1;i<=n;i++) p[i]=(s[i]&U)>>pos+1;
for(register int i=1;i<=n;i++) pre[0][p[i]]=pre[1][p[i]]=suf[1][p[i]]=suf[0][p[i]]=0;
}
else
{
for(register int i=1;i<=n;i++) lsh[i]=(s[i]&U)>>pos+1;
sort(lsh+1,lsh+n+1); cnt=unique(lsh+1,lsh+n+1)-lsh-1;
for(register int i=1;i<=cnt;i++) pre[0][i]=pre[1][i]=suf[1][i]=suf[0][i]=0;
for(register int i=1;i<=n;i++) p[i]=lower_bound(lsh+1,lsh+cnt+1,(s[i]&U)>>pos+1)-lsh;
}
for(register int i=1;i<=n;i++) suf[(s[i]>>pos)&1][p[i]]++;
for(register int i=1;i<=n;i++)
{
register int p1=(s[i]>>pos)&1;
suf[p1][p[i]]--; bas[p1^1]-=pre[p1^1][p[i]];
ans+=bas[p1];
pre[p1][p[i]]++; bas[p1]+=suf[p1^1][p[i]];
}
}
#undef int
int main()
{
#define int long long
freopen("xor.in","r",stdin); freopen("xor.out","w",stdout);
n=read(); for(int i=1;i<=n;i++) s[i]=read(),m=max(m,(int)log2(s[i]));
for(int i=0;i<=m;i++) solve(i); printf("%lld",ans);
return 0;
}

T3 异或 2

解题思路

此题需要高精,于是我掌握了 string 高精。。。

直接推一波柿子,其实还是比较好理解的。。

直接记忆化搜索实现即可,最多递归 log 层复杂度完全可以接受。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigend long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
inline void write(string x){reverse(x.begin(),x.end());for(auto it:x)putchar(it+'0');putchar('\n');}
string n; map<string,string> f;
string mul(string x,int val)
{
int lim=x.size(); string y; for(auto it:x) y.push_back(it*val); y.push_back(0);
for(int i=0;i<y.size()-1;i++) y[i+1]+=y[i]/10,y[i]%=10; if(!(*(--y.end()))) y.pop_back();
return y;
}
string add(string x,string y)
{
int lim=max(x.size(),y.size())+1; string z; for(int i=1;i<=lim;i++) z.push_back(0);
for(int i=0;i<x.size();i++) z[i]+=x[i]; for(int i=0;i<y.size();i++) z[i]+=y[i];
for(int i=0;i<z.size()-1;i++) z[i+1]+=z[i]/10,z[i]%=10; if(!(*(--z.end()))) z.pop_back();
return z;
}
string div(string x)
{
for(int i=0;i<x.size();i++){if((x[i]&1)&&i) x[i-1]+=5; x[i]/=2;}
if(!(*(--x.end()))) x.pop_back();
return x;
}
string del(string x,int val)
{
if(x[0]>=val) return x[0]-=val,x;
int pos=0;
for(int i=1;i<x.size();i++)
if(x[i]){x[pos=i]--;break;}
for(int i=pos-1;i>=1;i--) x[i]=9;
x[0]=x[0]+10-val;
return x;
}
string dfs(string x)
{
if(f.find(x)!=f.end()) return f.find(x)->second;
string k=div(x),temp;
if(x[0]&1) temp=add(mul(dfs(k),4),mul(k,6));
else temp=add(add(mul(dfs(k),2),mul(dfs(del(k,1)),2)),del(mul(x,2),4));
return f.insert(make_pair(x,temp)),temp;
}
#undef int
int main()
{
#define int long long
freopen("rox.in","r",stdin); freopen("rox.out","w",stdout);
cin>>n; reverse(n.begin(),n.end());
for(int i=0;i<n.size();i++) n[i]-='0';
string t1,t2; t1.clear(); t2.clear(); t1.push_back(0); t2.push_back(0); f.insert(make_pair(t1,t2));
t1.clear(); t1.push_back(1); f.insert(make_pair(t1,t2)); t1.clear(); t1.push_back(2); f.insert(make_pair(t1,t2));
t1.clear(); t2.clear(); t1.push_back(3); t2.push_back(6); f.insert(make_pair(t1,t2));
write(dfs(n));
return 0;
}

T4 卡牌游戏

解题思路

又是老脸买原题系列(虽然我没做过)

发现其实是若干个联通块,一个合法的联通块显然只能是基环树或者树,对于 -1 的情况直接并茶几根据点数边数关系判断即可。。

那么答案就是所有的联通块最小操作次数加和,方案数就是所有联通块的方案数乘积。

对于一个联通块而言,我们把牌的两边互相连边,边权分别赋值为 0 或者 1 ,那么最后的形态一定是一某个节点为根,所有的边都指向儿子。

对于树的情况直接换根 DP 即可,基环树的情况一定出现在环上的点为根的时候,直接统计。。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigend long long
#define f() cout<<"RP++"<<endl
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e5+10,INF=1e18,mod=998244353;
int n,ans1,ans2=1,cnt1,cnt2,id,banx,bany,du[N],fa[N],f[N],g[N];
int tot=1,head[N],ver[N<<1],nxt[N<<1],edge[N<<1];
bool vis[N];
pair<int,int> siz[N];
void add_edge(int x,int y,int val)
{
ver[++tot]=y; edge[tot]=val; du[y]++;
nxt[tot]=head[x]; head[x]=tot;
}
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
void dfs(int x,int fa)
{
vis[x]=true;
for(int i=head[x];i;i=nxt[i])
{
int to=ver[i]; if(to==fa) continue;
if(vis[to]){id=i;banx=x;bany=to;continue;}
dfs(to,x); f[x]+=edge[i]+f[to];
}
}
void dfs2(int x,int fa)
{
if(g[x]<cnt1) cnt1=g[x],cnt2=1;
else cnt2+=g[x]==cnt1;
for(int i=head[x];i;i=nxt[i])
if(ver[i]!=fa&&i!=id&&(i!=(id^1)))
if(edge[i]) g[ver[i]]=g[x]-1,dfs2(ver[i],x);
else g[ver[i]]=g[x]+1,dfs2(ver[i],x);
}
#undef int
int main()
{
#define int long long
freopen("card.in","r",stdin); freopen("card.out","w",stdout);
n=read();
for(int i=1,x,y;i<=n;i++)
x=read(),y=read(),
add_edge(x,y,1),add_edge(y,x,0);
for(int i=1;i<=2*n;i++) fa[i]=i,siz[i]=make_pair(1,du[i]);
for(int i=1;i<=n;i++)
{
int x=find(ver[i<<1]),y=find(ver[i<<1|1]); if(x==y) continue;
siz[y]=make_pair(siz[x].first+siz[y].first,siz[x].second+siz[y].second);
fa[x]=y;
}
for(int i=1;i<=2*n;i++)
if(find(i)==i&&siz[i].second>siz[i].first*2)
printf("-1 -1"),exit(0);
for(int i=1;i<=2*n;i++)
{
if(vis[i]) continue; cnt1=INF; cnt2=id=0;
dfs(i,0); g[i]=f[i]; dfs2(i,0);
if(!id){ans1+=cnt1;ans2=ans2*cnt2%mod;continue;}
int t1=g[banx]+(edge[id]^1),t2=g[bany]+edge[id];
ans1+=min(t1,t2); if(t1==t2) ans2=ans2*2%mod;
}
printf("%lld %lld",ans1,ans2);
return 0;
}

NOIP模拟96(多校29)的更多相关文章

  1. NOIP模拟83(多校16)

    前言 CSP之后第一次模拟赛,感觉考的一般. 不得不吐槽多校联测 OJ 上的评测机是真的慢... T1 树上的数 解题思路 感觉自己思维有些固化了,一看题目就感觉是线段树. 考完之后才想起来这玩意直接 ...

  2. NOIP模拟92(多校25)

    前言 所以说这次是 HZOI 多校联测巅峰????(题目,数据过水??) T1 石子合并 解题思路 签到题. 发现我们可以给每个数字附一个正负号,每个数字的贡献就是它本身乘上这个符号. 发现至少应该有 ...

  3. NOIP模拟84(多校17)

    T1 宝藏 解题思路 考场上一眼出 \(nlog^2\) 做法,然后没看见是 1s 3e5 的数据,我竟然以为自己切了?? 考完之后尝试着把二分改为指针的移动,然后就过了??或许是数据水吧,感觉自己的 ...

  4. NOIP模拟85(多校18)

    前言 好像每个题目背景所描述的人都是某部番里的角色,热切好像都挺惨的(情感上的惨). 然后我只知道 T1 的莓,确实挺惨... T1 莓良心 解题思路 首先答案只与 \(w\) 的和有关系,于是问题就 ...

  5. NOIP模拟86(多校19)

    T1 特殊字符串 解题思路 \(f_{i,j}\) 表示前 \(i\) 个字符中结尾为 \(j\) 的最大贡献. 转移枚举当前位置于之前位置结尾的组合加上贡献即可. 对于边界问题,容易发现选择 1 一 ...

  6. NOIP模拟88(多校21)

    前言 对于这套题的总体感觉就是难,然后就是自己很菜... 对于 T1 考试时只会一个最垃圾的背包,考完之后对于思路这一块也不是很顺利,大概这就是薄弱的地方吧. 然后 T2 是比较简单的一道题了,但是考 ...

  7. NOIP模拟99(多校31)

    T1 法阵 解题思路 原题3100,张口放 T1(出题人原话) 思维题,合法的情况其实就是上下两个梯形拼起来的样子. 他们的边界都是在 \(i\) 轴上面,但是不能相交. 于是我们可以尝试两者相交的纵 ...

  8. Nescafe #29 NOIP模拟赛

    Nescafe #29 NOIP模拟赛 不知道这种题发出来算不算侵权...毕竟有的题在$bz$上是权限题,但是在$vijos$似乎又有原题...如果这算是侵权的话请联系我,我会尽快删除,谢谢~ 今天开 ...

  9. noip模拟29[简单的板子题](虽然我不会)

    \(noip模拟29\;solutions\) 这次考试给我最大的伤害,让我意识到了差距 这场考试可以说是非常的简单,就是简单到,看两眼,打个表就有结果了 但是呢?我考得非常的完蛋,只有30pts 据 ...

随机推荐

  1. CF848E-Days of Floral Colours【dp,分治NTT】

    正题 题目链接:https://www.luogu.com.cn/problem/CF848E 题目大意 \(2n\)个花排成一个圆环,\(n\)种颜色每种两个,要求两个相同颜色之间最小距离为\(1, ...

  2. CentOS7 Docker容器无法ping通宿主机ip问题解决记录

    Docker服务部署启动容器发现docker容器内访问宿主机IP不通,于是进入容器内ping宿主机IP,发现无法ping通,容器IP为172.17.0.2,于是继续ping172.17.0.1也不通, ...

  3. CSS 小技巧 | 一行代码实现头像与国旗的融合

    到国庆了,大家都急着给祖国母亲庆生. 每年每到此时,微信朋友圈就会流行起给头像装饰上国旗,而今年又流行这款: emm,很不错. 那么,将一张国旗图片与我们的头像,快速得到想要的头像,使用 CSS 如何 ...

  4. DistSQL:像数据库一样使用 Apache ShardingSphere

    Apache ShardingSphere 5.0.0-beta 深度解析的第一篇文章和大家一起重温了 ShardingSphere 的内核原理,并详细阐述了此版本在内核层面,特别是 SQL 能力方面 ...

  5. js 改变this指向的三种方法 bind call apply

    先了解下bind call apply 的注意点 bind 需要手动调用 第一个参数 this 要指向的对象,后面是 散列的参数 call 不需要手动调用 第一个参数 this 要指向的对象,后面是 ...

  6. SpringBoot整合JDBC-调用数据库

    SpringData 对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理. Sprin ...

  7. 写学习abcde的简单AI(C++实现)

    #include <iostream> #include <time.h> #include <stdlib.h> #include <cmath> u ...

  8. Redis 面试常见问题———缓存雪崩、缓存击穿以及缓存穿透

    在开发中会面临缓存异常可能会出现三个问题,分别是缓存雪崩.缓存击穿和缓存穿透.这三个问题会导致大量请求从缓存转移到数据库,如果请求的并发量很大的话,就会导致数据库崩溃.所以在面试官也会经常问这些问题. ...

  9. Java(2)详解注释&关键字&常量&变量&标识符

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201497.html 博客主页:https://www.cnblogs.com/testero ...

  10. 【转】对于编译程序时出现“Deprecated declaration ultrasonic_Init - give arg types”的解决办法

    编译程序时出现"Deprecated declaration ultrasonic_Init - give arg types"中文释义:给定函数的参数的类型过时, 解决办法: 在 ...