多校冲刺 NOIP 20211113 模拟 (29)
T4原题忘记如何统计答案,被迫暴力。。。。
T1 子集和
签到题,直接背包就行了
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){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 maxn=1e5+5;
int n,b[maxn],m,a[maxn],top;
int bb[maxn],sum;
signed main()
{
freopen("subset.in","r",stdin);
freopen("subset.out","w",stdout);
n=read();m=read();
for(int i=0;i<=m;i++) b[i]=read();
int tmp=1; bb[0]=1;
while(tmp<=m)
{
while(!b[tmp]) tmp++;
int num=b[tmp]-bb[tmp];
if(num)
{
int x=tmp;
for(int i=1;i<=num;i++)
{
a[++top]=tmp;
for(int v=m;v>=tmp;v--)
bb[v]+=bb[v-tmp];
}
}
tmp++;
}
for(int i=1;i<=top;i++) printf("%lld ",a[i]);
}
T2 异或
有许多不同的做法,这里给出我考场上的做法,
我们首先对所有点建出一棵 \(Trie\) 树,再将每个点依次删掉顺便统计答案,
答案肯定是被删的与没有被删的点组合出的答案,那么再维护这个点被删掉的与没有被删掉的个数
以及这一层所有左子树删掉的与右子树没被删掉的乘积和,右子树删掉与左子树没被删掉的乘积和
然后统计答案就好了
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){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 maxn=5e5+5;
int a[maxn],n;
namespace sub{
ll ans=0;
struct Trie{
int tr[maxn*30][2],root,cnt,ws[maxn*30],ys[maxn*30];ll cj[40][2];
inline void init(){cnt=1;root=1;}
inline void insert(int x)
{
int u=root;
for(int i=30;i>=0;i--)
{
int val=(x&(1<<i))?1:0;
if(x&(1<<i)) val=1;
else val=0;
ws[u]++;
if(!tr[u][val]) tr[u][val]=++cnt;
u=tr[u][val];
}
ws[u]++;
}
inline void getans(int x)
{
int u=root;
for(int i=30;i>=0;i--)
{
int val=(x&(1<<i))?1:0;
if(x&(1<<i)) val=1;
else val=0;
ws[u]--;ys[u]++;
if(val) ans+=cj[i][0]; else ans+=cj[i][1];
if(val)
{
cj[i][1]-=1ll*ws[tr[u][1]]*ys[tr[u][0]];
cj[i][1]+=1ll*(ws[tr[u][1]]-1)*ys[tr[u][0]];
cj[i][0]-=1ll*ws[tr[u][0]]*ys[tr[u][1]];
cj[i][0]+=1ll*ws[tr[u][0]]*(ys[tr[u][1]]+1);
}
else
{
cj[i][1]-=1ll*ws[tr[u][1]]*ys[tr[u][0]];
cj[i][1]+=1ll*ws[tr[u][1]]*(ys[tr[u][0]]+1);
cj[i][0]-=1ll*ws[tr[u][0]]*ys[tr[u][1]];
cj[i][0]+=1ll*(ws[tr[u][0]]-1)*ys[tr[u][1]];
}
u=tr[u][val];
}
ws[u]--;ys[u]++;
}
}T;
inline void main()
{
T.init();
for(int i=1;i<=n;i++) T.insert(a[i]);
for(int i=1;i<=n;i++) T.getans(a[i]);
printf("%lld\n",ans);
}
}
signed main()
{
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
n=read();
for(int i=1;i<=n;i++) a[i]=read();
sub::main();return 0;
}
T3 异或 2
知道个柿子就能70了,剩下就是写高精,真jb烦
Code
#include<bits/stdc++.h>
#define LL __int128
#define ULL __uint128_t
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){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 base=10000000000000000ll;
struct gj{
int l,c[101]; ULL has; gj(){}
gj(int x){memset(c,0,sizeof(c));l=1;c[1]=x;}
inline void geths(){has=l; for(int i=1;i<=l;i++) has*=c[i];}
inline void print(){printf("%lld",c[l]);for(int i=l-1;i>0;i--)printf("%016lld",c[i]);puts("");}
inline gj operator+(const gj &a)const
{
gj res=gj(0); res.l=max(l,a.l); for(int i=1;i<=res.l;i++)
{res.c[i]+=c[i]+a.c[i];res.c[i+1]+=res.c[i]/base;res.c[i]%=base;}
if(res.c[res.l+1]) ++res.l; res.geths(); return res;
}
inline gj operator-(const int &a)const
{
gj res=gj(0);res.l=l;for(int i=1;i<=l;i++)res.c[i]=c[i];
int pos=1;res.c[1]-=a;
while(res.c[pos]<0){res.c[pos]+=base;++pos;--res.c[pos];}
if(!res.c[res.l])--res.l;res.geths();return res;
}
inline gj operator*(const int &a)const
{
gj res=gj(0); res.l=l;for(int i=1;i<=res.l;i++)
{res.c[i]+=c[i]*a;res.c[i+1]+=res.c[i]/base;res.c[i]%=base;}
if(res.c[res.l+1])++res.l;res.geths();return res;
}
inline gj operator/(const int &a)const
{
gj res=gj(0);res.l=l;for(int i=1;i<=l;i++)res.c[i]=c[i];
if(res.c[1]&1)--res.c[1];
for(int i=l;i;i--){if(res.c[i]&1) res.c[i-1]+=base;res.c[i]/=a;}
if(!res.c[l]) --res.l; res.geths(); return res;
}
}n;
map<ULL,gj>mp;
inline gj Read()
{
char ch[1000];
gj res=gj(0); scanf("%s",ch+1); int len=strlen(ch+1);
for(int i=1;i<=len;i++) res=res*10+gj(ch[i]-'0');
return res;
}
inline gj dfs(gj now)
{
if(now.l<=1&&now.c[1]<=0) return mp[now.has]=gj(0);
if(mp.find(now.has)!=mp.end()) return mp[now.has];
gj k=now/2;if(now.c[1]&1) mp[now.has]=dfs(k)*4+k*6;
else mp[now.has]=dfs(k)*2+dfs(k-1)*2+k*4-4;
return mp[now.has];
}
signed main()
{
freopen("rox.in","r",stdin);
freopen("rox.out","w",stdout);
gj n=Read();dfs(n).print();
}
T4 卡牌游戏
原题,基环树+换根dp,对于每个联通块求出最小结果及其方案,乘一块就行了
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){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 maxn=2e5+5,mod=998244353;
int head[maxn],f[3][maxn],num=1,n,m;
struct edge{int to,nxt,v;}e[maxn<<1];
inline void add(int x,int y,int val)
{e[++num]=(edge){y,head[x],val};head[x]=num;}
namespace solve1{
int dian,bian;bool vis[maxn];
inline void dfs(int x,int fa)
{
dian++;vis[x]=1;for(int i=head[x];i;i=e[i].nxt)
{bian++;int y=e[i].to;if(y!=fa&&!vis[y])dfs(y,x);}
}
inline bool pd()
{
memset(vis,0,sizeof(vis));for(int i=1;i<=n*2;i++)
if(!vis[i]){dian=bian=0;dfs(i,0);if(dian*2<bian)return false;}
return true;
}
}
namespace solve2{
bool v[maxn];vector<int>tmp;
int st,en,ned;
inline void dfs1(int x,int fa)
{
v[x]=1;f[1][x]=0;for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa){int y=e[i].to;
if(!v[y]){dfs1(y,x);f[1][x]+=f[1][y]+e[i].v;}
else st=x,en=y,ned=i;}
}
inline void dfs2(int x,int fa)
{
tmp.push_back(f[2][x]);
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa&&i!=ned&&i!=(ned^1))
{
int y=e[i].to;
if(e[i].v) f[2][y]=f[2][x]-1;
else f[2][y]=f[2][x]+1;
dfs2(y,x);
}
}
signed ppp()
{
int minn=0,ans=0,ans2=1;
for(int i=1;i<=2*n;i++)
if(!v[i])
{
st=en=ned=-1;tmp.clear();minn=0;
dfs1(i,0);f[2][i]=f[1][i];dfs2(i,0);
if(st==-1)
{
sort(tmp.begin(),tmp.end());
for(int i=0;i<tmp.size();i++)
if(tmp[i]==tmp[0])minn++;else break;
ans+=tmp[0];
}
else
{
ned%=2;
if(f[2][st]+ned==f[2][en]+(ned^1)) minn=2;
else minn=1;
ans+=min(f[2][st]+ned,f[2][en]+(ned^1));
}
ans2=(ans2*minn)%mod;
}
printf("%lld %lld\n",ans,ans2);
return 0;
}
}
signed main()
{
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
n=read();num=1;
for(int i=1;i<=n;i++)
{
int x=read(),y=read();
add(x,y,1);
add(y,x,0);
}
if(!solve1::pd()){puts("-1 -1");return 0;}
solve2::ppp();
}