多校冲刺 noip 11.13
多校冲刺 noip 11.13
我改题速度还是慢,慢死了
别人都改完了,我也改不完,我......
今天暴露很多问题,比如考场心态不稳,全靠第一题
比如数位\(DP\)根本不会,比如基环树学的像屎一样
T1 子集和
如果凑不够的话,只能加当前的数,不断地背包就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*f;
}
const int N=55;
const int M=10005;
int n,m;
int a[N],cnt,b[M],v[M];
signed main(){
freopen("subset.in","r",stdin);
freopen("subset.out","w",stdout);
n=read();m=read();
fo(i,0,m)b[i]=read();
v[0]=1;
fo(i,0,m){
int now=b[i]-v[i];
if(!now)continue;
while(now){
a[++cnt]=i;
fu(j,m,i)v[j]+=v[j-i];
now=b[i]-v[i];
}
}
fo(i,1,n)printf("%d ",a[i]);
return 0;
}
T2 异或
一开始确实看错题了,以为一遍\(dfs\)就能解决
后来看出来之后,我一度想在\(trie\)树上放个线段树
转念一想发现可以直接用两颗\(trie\),枚举\(j\),动态更新答案就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*f;
}
const int N=5e5+5;
int n,a[N];
ll ans,an[35][2];
struct TRIE{
int son[N*32][2],siz[N*32];
int seg=1;
}t[2];
void ins(int x,int id){
int now=1;
fu(i,30,0){
int tmp=(x>>i)&1;
if(!t[id].son[now][tmp])t[id].son[now][tmp]=++t[id].seg;
an[i][0]-=1ll*t[0].siz[t[0].son[now][0]]*t[1].siz[t[1].son[now][1]];
an[i][1]-=1ll*t[0].siz[t[0].son[now][1]]*t[1].siz[t[1].son[now][0]];
t[id].siz[t[id].son[now][tmp]]++;
an[i][0]+=1ll*t[0].siz[t[0].son[now][0]]*t[1].siz[t[1].son[now][1]];
an[i][1]+=1ll*t[0].siz[t[0].son[now][1]]*t[1].siz[t[1].son[now][0]];
now=t[id].son[now][tmp];
//cout<<id<<" "<<x<<" "<<i<<" "<<now<<endl;
}
}
void del(int x,int id){
int now=1;
fu(i,30,0){
int tmp=(x>>i)&1;
an[i][0]-=1ll*t[0].siz[t[0].son[now][0]]*t[1].siz[t[1].son[now][1]];
an[i][1]-=1ll*t[0].siz[t[0].son[now][1]]*t[1].siz[t[1].son[now][0]];
t[id].siz[t[id].son[now][tmp]]--;
an[i][0]+=1ll*t[0].siz[t[0].son[now][0]]*t[1].siz[t[1].son[now][1]];
an[i][1]+=1ll*t[0].siz[t[0].son[now][1]]*t[1].siz[t[1].son[now][0]];
now=t[id].son[now][tmp];
}
}
signed main(){
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
// cerr<<(sizeof(t)+sizeof(a)+sizeof(an)>>20)<<endl;
n=read();
fo(i,1,n)a[i]=read(),ins(a[i],1);
fo(i,1,n){
del(a[i],1);
fu(j,30,0)ans+=an[j][(a[i]>>j)&1];
ins(a[i],0);
}
printf("%lld",ans);
return 0;
}
T3 异或2
这个可以直接推式子??
也也可以数位\(DP\),这个主要思想是看有没有进位,然后退回去,计算方案数乘贡献就行了
这是摇摆\(B\)的思路
我直接推式子了,额,我不想写
需要高精度!!!!!
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int bas=1e16;
struct BIG{
int x[155];
BIG(){memset(x,0,sizeof(x));}
void read(){
char ch[1805];
scanf("%s",ch+1);
int len=strlen(ch+1);
x[0]=(len-1)/16+1;
fo(i,1,len){
int now=len+1-i;
int pos=(now-1)/16+1;
x[pos]=(x[pos]<<3)+(x[pos]<<1)+ch[i]-'0';
}
}
void write(){
printf("%lld",x[x[0]]);
fu(i,x[0]-1,1)printf("%016lld",x[i]);
putchar('\n');
}
bool operator < (BIG a)const{
if(x[0]!=a.x[0])return x[0]<a.x[0];
fu(i,x[0],1)if(x[i]!=a.x[i])return x[i]<a.x[i];
return false;
}
BIG operator * (int s)const{
BIG ret;int jw;
fo(i,1,x[0]){
ret.x[i]+=x[i]*s;
ret.x[i+1]+=ret.x[i]/bas;
ret.x[i]=ret.x[i]%bas;
}
if(ret.x[x[0]+1])ret.x[0]=x[0]+1;
else ret.x[0]=x[0];
return ret;
}
BIG operator + (BIG a)const{
BIG ret;
fo(i,1,max(x[0],a.x[0])){
ret.x[i]+=x[i]+a.x[i];
ret.x[i+1]+=ret.x[i]/bas;
ret.x[i]=ret.x[i]%bas;
}
if(ret.x[max(x[0],a.x[0])+1])ret.x[0]=max(x[0],a.x[0])+1;
else ret.x[0]=max(x[0],a.x[0]);
return ret;
}
BIG operator + (int s)const{
BIG ret=*this;
ret.x[1]+=s;
fo(i,1,x[0]){
ret.x[i+1]+=ret.x[i]/bas;
ret.x[i]=ret.x[i]%bas;
}
if(ret.x[x[0]+1])ret.x[0]=x[0]+1;
else ret.x[0]=x[0];
return ret;
}
BIG operator - (BIG a)const{
BIG ret;
fo(i,1,x[0]){
ret.x[i]+=x[i]-a.x[i];
if(ret.x[i]<0)ret.x[i]+=bas,ret.x[i+1]-=1;
}
ret.x[0]=x[0];
while(!ret.x[ret.x[0]]&&ret.x[0]>1)ret.x[0]--;
return ret;
}
BIG operator - (int s)const{
BIG ret=*this;
ret.x[1]-=s;
fo(i,1,x[0]){
if(ret.x[i]>=0)break;
ret.x[i+1]--;
ret.x[i]+=bas;
}
if(!ret.x[x[0]]&&x[0]>1)ret.x[0]=x[0]-1;
else ret.x[0]=x[0];
return ret;
}
BIG operator / (int s)const{
BIG ret=*this;
fu(i,x[0],2){
if(ret.x[i]&1)ret.x[i-1]+=bas;
ret.x[i]>>=1;
}
ret.x[1]>>=1;
if(!ret.x[x[0]])ret.x[0]=x[0]-1;
else ret.x[0]=x[0];
return ret;
}
}n,ans;
map<BIG,BIG> mp;
BIG dfs(BIG x){
if(mp.find(x)!=mp.end())return mp[x];
if(x.x[0]==1&&x.x[1]==1){
mp[x].x[0]=1;mp[x].x[1]=2;
return mp[x];
}
if(x.x[0]==1&&x.x[1]==0){
mp[x].x[0]=1;mp[x].x[0]=0;
return mp[x];
}
if(x.x[1]&1)return mp[x]=dfs(x/2)*4+x+1;
else return mp[x]=dfs(x/2)*2+dfs(x/2-1)*2;
}
signed main(){
freopen("rox.in","r",stdin);
freopen("rox.out","w",stdout);
n.read();
ans=dfs(n)-n*2;
ans.write();
return 0;
}
T4 卡牌游戏
发现如果从正面向反面连边,那么每个点至多有一条出边
所以我们对边进行反转,相当于对卡牌进行翻转
直接统计答案就好了
对我的基环树\(DP\)有了很大的提升
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*f;
}
const int N=2e5+5;
const int mod=998244353;
int n,ans1,ans2=1;
int to[N*2],nxt[N*2],val[N*2],head[N*2],rp=1;
void add_edg(int x,int y,int z){
to[++rp]=y;
val[rp]=z;
nxt[rp]=head[x];
head[x]=rp;
}
bool vis[N],cat[N];
int dp[N];
int dfs_rt(int x,int f){
int ret=0;
for(int i=head[x];i;i=nxt[i]){
if(cat[i])continue;
int y=to[i];
if(y==f)continue;
ret+=dfs_rt(y,x);
ret+=val[i];
}
return ret;
}
int mn,sum;
void dfs_oth(int x,int f){
if(mn>dp[x])mn=dp[x],sum=1;
else if(mn==dp[x])sum++;
for(int i=head[x];i;i=nxt[i]){
if(cat[i])continue;
int y=to[i];
if(y==f)continue;
if(val[i])dp[y]=dp[x]-1;
else dp[y]=dp[x]+1;
dfs_oth(y,x);
}
}
int s,t,b;
bool flag=true;
void dfs_cir(int x,int f){
vis[x]=true;
for(int i=head[x];i;i=nxt[i]){
if(cat[i])continue;
int y=to[i];
if(y==f)continue;
if(vis[y]){
cat[i]=cat[i^1]=true;
if(s)flag=false;
s=x;t=y;b=i;
continue;
}
dfs_cir(y,x);
}
}
signed main(){
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
n=read();
fo(i,1,n){
int x=read(),y=read();
add_edg(x,y,1);
add_edg(y,x,0);
}
fo(i,1,2*n){
if(vis[i]||!head[i])continue;
s=t=0;dfs_cir(i,0);
if(!s){
dp[i]=dfs_rt(i,0);
mn=0x3f3f3f3f3f3f3f3f;sum=1;
dfs_oth(i,0);
ans1+=mn;ans2=ans2*sum%mod;
//cerr<<mn<<endl;
}
else {
//cerr<<"fuck"<<endl;
dp[i]=dfs_rt(i,0);
dfs_oth(i,0);
if(s!=t){
if(b&1)dp[to[b^1]]++;
else dp[to[b]]++;
}
if(dp[s]==dp[t]&&s!=t)ans1+=dp[s],ans2=ans2*2%mod;
else ans1+=min(dp[s],dp[t]);
}
}
cerr<<ans1<<" "<<ans2<<endl;
if(!flag)ans1=ans2=-1;
printf("%lld %lld",ans1,ans2);
}
QQ:2953174821