ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

模拟[忘了编号]考试总结

2021-11-14 08:33:34  阅读:86  来源: 互联网

标签:return int res len Int base 模拟 编号 考试


发现两套模拟赛编号乱了,于是先懒得改了
又咕了亿篇题解,rp--

考试经过

noip全真环境,就是键盘不太顺手
开场T1想到背包,于是做个退背包就切了,T2想到trie,一直执着于枚举中间的\(j\),搞到9点半发现好像假了,每次处理都要遍历整棵树,觉得调下去没啥戏就写了小常数\(n^3\)暴力拿40,时限3s根本不虚
T3打表发现了规律,于是写了70,高精显然没有能力冲上,于是开T4
发现T4是原题,然而做法不太记得,回忆的差不多已经十一点半了,想试试能不能冲上,不行也有-1,于是开冲。在冲上2个dp之后成功换根绕晕自己,最后检查文件草草了事
下午发现T3CE了,原来__int128不支持abs函数,还是不要偷懒了吧
战神AK了,一堆人300+,T4一个-1都没有,垫底了

T1.子集和

直接枚举复杂度是指数的,观察数据发现正解复杂度在\(nm\)左右
把过程逆过来就是一个01背包拼方案的过程,所以倒回去就行了,每次把对应方案减去,剩下是1的加入答案

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int M=10005;
int a[M],n,m;
signed main()
{
	freopen("subset.in","r",stdin);
	freopen("subset.out","w",stdout);
	cin>>n>>m;
	for(int i=0;i<=m;i++)scanf("%lld",&a[i]);
	int p=1;
	for(int i=1;i<=n;i++)
	{	
		while(a[p]==0&&p<m)p++;
		for(int j=p;j<=m;j++)
		  a[j]-=a[j-p];
		printf("%lld ",p);
	}
	return 0;
}	

T2.异或

trie很正确,但是后面的思路就不对了,没有及时调整
异或比大小,高位碾压低位,所以从高到低考虑,找与他不同的,显然01trie
应该枚举\(k\)的位置来确定\(i\)和\(j\),那么\(i\)会被限制在他兄弟的子树\(pos\)里有两种情况
1.\(j\)也在子树里,这种情况可以随便选,但是有先后顺序的问题所以要除以2,贡献是\(sz_{pos}\times (sz_{pos}-1)/2\)
2.\(j\)在子树外,这里要求\(j\)在这一位对应的数要和\(k\)相异,就是和\(i\)相同,开数组记录每一位是\(0/1\)的数量,然后减去子树内\(sz\),由于要考虑\(j>i\)的情况,所以可以在插入每个数的时候处理出对应的\(j<i\)数量,然后减去即可
很久没做trie,思路不到,应该把早时候的一些补一下

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=500050;
int a[N],n,tr[31*N][2],sum[60*N],tot=1;
int s[31][2],ss[60*N];long long ans;
inline void add(int x)
{
	int now=1;
	for(int i=30;i>=1;i--)
	{
		int p=((x>>(i-1))&1);
		if(!tr[now][p])tr[now][p]=++tot;
		now=tr[now][p];ss[now]+=s[i][p]-sum[now];
		sum[now]++;s[i][p]++;
	}
}
inline void dfs(int x)
{	
	int now=1;
	for(int i=30;i>=1;i--)
	{	
		int p=((x>>(i-1))&1),pp=p^1;
		if(!tr[now][p])tr[now][p]=++tot;
		ans+=(1ll*sum[tr[now][pp]]*(sum[tr[now][pp]]-1))/2;
		ans+=(1ll*s[i][pp]-sum[tr[now][pp]])*sum[tr[now][pp]]-ss[tr[now][pp]];
		now=tr[now][p];
	}
}
signed main()
{
	freopen("xor.in","r",stdin);
	freopen("xor.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)dfs(a[i]),add(a[i]);
	cout<<ans<<endl;
	return 0;
}

T3.异或2

考场没想正解,打表发现贡献可以按照每一位单独算,第\(i\)位按照\(n\mod 2^i\)分组,每组是一个等差数列,前一半首项是0,后面依次增加2,公差从中间往两边递增,对着表简单算一下就能解决
然而高精是恶心的,这个方法要高精除和高精取模,高精除高精TLE成狗,于是他死了
题解还是厉害啊,推了一波式子,最后转化成了一个递归式,每次记忆化搜索就行了
image
image
看明白一个地方就是在第一个式子把2变成4的时候用了异或的性质,相当于直接把最后一位的贡献处理掉了,然后整体右移1位操作,比较神仙,下面的式子提中括号的时候也是一样,最后一位的贡献上边是1,下边是0
所以应该就做完了,高精需要高精加减,高精乘高精,高精除2,以及比较大小(记忆化用map
然而开始沉迷于高精除高精疯狂百度各种模版,最后失去信仰了就换做法了,没有手打高精rp--
放上一个高精全家桶吧找万能的谷民要的

class Int{
    #define BASE 1000000000
    public:
    typedef long long value;
    void New(size_t l){
        if (a!=NULL)delete[] a;a=new value[l];
        len=1;a[0]=0;sign=1;
    }
    Int():a(NULL),base(BASE){New(1);}
    Int(value x):a(NULL),base(BASE){New(1);*this=x;}
    Int(value x,value _base):a(NULL),base(_base){New(1);*this=x;}
    Int(const Int &B):a(NULL),base(BASE){New(1);*this=B;}
    ~Int(){delete[] a;}
    Int& operator =(value x){
        size_t l=1;for (value x1=max(x,-x);x1>=base;++l,x1/=base);New(l);
        if (x<0)x=-x,sign=0;else sign=1;
        len=0;while (x)a[len++]=x%base,x/=base;
        if (!len)a[len++]=0;
        return *this;
    }
    Int& operator =(const Int &A){
        New(A.len);len=A.len;memcpy(a,A.a,sizeof(value)*len);
        base=A.base;sign=A.sign;return *this;
    }
    friend Int operator -(Int A){A.sign=1-A.sign;return A;}
    bool operator !(){if (len==1&&a[0]==0)return 1;else return 0;}
    friend Int operator +(Int A,Int B){
        if (A.sign!=B.sign){B.sign=1-B.sign;return A-B;}
        if (A.base!=B.base)
            if (A.base>B.base)B.set_base(A.base);
            else A.set_base(B.base);
        Int res;res.set_base(A.base); int len=A.len>B.len?A.len:B.len;
        res.New(len+1);res.sign=A.sign;
        memset(res.a,0,(len+1)*sizeof(value));
        for (int i=0;i<len;++i){
            if (i<A.len)res.a[i]+=A.a[i];
            if (i<B.len)res.a[i]+=B.a[i];
        }
        for (int i=0;i<len;++i)
            if (res.a[i]>=res.base)++res.a[i+1],res.a[i]-=res.base;
        if (res.a[len])res.len=len+1;else res.len=len;
        if (!res)res.sign=1;return res;
    }
    friend Int operator -(Int A,Int B){
        if (A.sign!=B.sign){B.sign=1-B.sign;return A+B;}
        if (A.base!=B.base)
            if (A.base>B.base)B.set_base(A.base);
            else A.set_base(B.base);
        if (small(A,B))swap(A,B),A.sign=1-A.sign;
        Int res;res.set_base(A.base); int len=A.len>B.len?A.len:B.len;
        res.New(len);res.sign=A.sign;
        memset(res.a,0,len*sizeof(value));
        for (int i=0;i<len;++i){
            if (i>=B.len)res.a[i]+=A.a[i];
            else res.a[i]+=A.a[i]-B.a[i];
            if (res.a[i]<0)res.a[i]+=res.base,--res.a[i+1];
        }
        while (len>1&&!res.a[len-1])--len;res.len=len;
        if (!res)res.sign=1;return res;
    }
    friend Int operator *(Int A,Int B){
        if (A.base!=B.base)
            if (A.base>B.base)B.set_base(A.base);
            else A.set_base(B.base);
        Int res;res.set_base(A.base); int len=A.len+B.len;
        res.New(len);res.sign=(A.sign==B.sign);
        memset(res.a,0,len*sizeof(value));
        for (int i=0;i<A.len;++i)
            for (int j=0;j<B.len;++j){
                res.a[i+j]+=A.a[i]*B.a[j];
                res.a[i+j+1]+=res.a[i+j]/res.base;
                res.a[i+j]%=res.base;
            }
        /*
        for (int i=0;i<A.len;++i)
            for (int j=0;j<B.len;++j)res.a[i+j]+=A.a[i]*B.a[j];
        for (int i=0;i<len-1;++i)res.a[i+1]+=res.a[i]/res.base,res.a[i]%=res.base;
        */
        while (len>1&&!res.a[len-1])--len;res.len=len;
        return res;
    }
    friend pair<Int,Int> divide(Int A,Int B){
        if (!B){puts("error:div zero!");for (;;);}
        if (A.base!=B.base)
            if (A.base>B.base)B.set_base(A.base);
            else A.set_base(B.base);
        if (small(A,B))return make_pair(Int(0),A);
        Int C,D;C.set_base(A.base);D.set_base(A.base);C.New(A.len);C.len=A.len;
        bool Csign=(A.sign==B.sign),Dsign=A.sign;A.sign=B.sign=1;
        for (int i=A.len-1;i>=0;--i){
            C.a[i]=0;D=D*D.base;D.a[0]=A.a[i];
            int l=0,r=A.base-1,mid;
            while (l<r){
                mid=(l+r+1)>>1;
                if (small(B*mid,D+1))l=mid;
                    else r=mid-1;
            }
            C.a[i]=l;D=D-B*l;
        }
        C.sign=Csign;D.sign=Dsign;if (!D)D.sign=1;
        while (C.len>1&&!C.a[C.len-1])--C.len;
        return make_pair(C,D);
    }
    Int operator /(value x){
        if (!x){puts("error:div zero!");for (;;);}
        value d=0;Int res;res.set_base(base);res.New(len);res.len=len;
        if (x<0)x=-x,res.sign=(sign==0);
        else res.sign=(sign==1);
        for (int i=len-1;i>=0;--i)
            d=d*base+a[i],res.a[i]=d/x,d%=x;
        while (res.len>1&&!res.a[res.len-1])--res.len;
        return res;
    }
    Int operator %(value x){
        value d=0;if (x<0)x=-x;
        for (int i=len-1;i>=0;--i)d=(d*base+a[i])%x;
        return d;
    }
    friend Int abs(Int A){A.sign=1;return A;}
    friend bool small(Int A,Int B){
        if (A.base!=B.base)
            if (A.base>B.base)B.set_base(A.base);
            else A.set_base(B.base);
        if (A.len!=B.len)return A.len<B.len;
        for (int i=A.len-1;i>=0;--i)
            if (A.a[i]!=B.a[i])return A.a[i]<B.a[i];
        return 0;
    }
    friend bool operator <(Int A,Int B){
        if (A.sign!=B.sign)return A.sign<B.sign;
        return A.sign==1?small(A,B):small(B,A);
    }
    friend bool operator ==(Int A,Int B){
        if (A.base!=B.base)
            if (A.base>B.base)B.set_base(A.base);
            else A.set_base(B.base);
        if (A.sign!=B.sign||A.len!=B.len)return 0;
        for (int i=0;i<A.len;++i)if (A.a[i]!=B.a[i])return 0;
        return 1;
    }
    friend bool operator !=(Int A,Int B){return !(A==B);}
    friend bool operator >(Int A,Int B){return !(A<B||A==B);}
    friend bool operator <=(Int A,Int B){return A<B||A==B;}
    friend bool operator >=(Int A,Int B){return A>B||A==B;}
    Int operator /(Int B){return divide(*this,B).first;}
    Int operator %(Int B){return divide(*this,B).second;}
    Int& operator +=(Int B){*this=*this+B;return *this;}
    Int& operator -=(Int B){*this=*this-B;return *this;}
    Int& operator *=(Int B){*this=*this*B;return *this;}
    Int& operator /=(Int B){*this=*this/B;return *this;}
    Int& operator %=(Int B){*this=*this%B;return *this;}
    Int& operator ++(){*this=*this+1;return *this;}
    Int& operator --(){*this=*this-1;return *this;}
    Int operator ++(int){Int res(*this);*this=*this+1;return res;}
    Int operator --(int){Int res(*this);*this=*this-1;return res;}
    Int operator +(value x){return *this+Int(x,this->base);}
    Int operator -(value x){return *this-Int(x,this->base);}
    Int operator *(value x){return *this*Int(x,this->base);}
    //Int operator /(value x){Int T;T=x;return *this/T;}
    //Int operator %(value x){Int T;T=x;return *this%T;}
    Int& operator *=(value x){*this=*this*x;return *this;}
    Int& operator +=(value x){*this=*this+x;return *this;}
    Int& operator -=(value x){*this=*this-x;return *this;}
    Int& operator /=(value x){*this=*this/x;return *this;}
    Int& operator %=(value x){*this=*this%x;return *this;}
    bool operator ==(value x){return *this==Int(x,this->base);}
    bool operator !=(value x){return *this!=Int(x,this->base);}
    bool operator <=(value x){return *this<=Int(x,this->base);}
    bool operator >=(value x){return *this>=Int(x,this->base);}
    bool operator <(value x){return *this<Int(x,this->base);}
    bool operator >(value x){return *this>Int(x,this->base);}
    friend Int gcd(Int x,Int y){
        Int t;int cnt=0;
        while (1){
            if (x<y)t=x,x=y,y=t;
            if (y==0){
                while (cnt--)x*=2;
                return x;
            }
            if (x%2==0&&y%2==0)x/=2,y/=2,++cnt;
            else if (x%2==0)x/=2;
            else if (y%2==0)y/=2;
            else {t=x;x=y;y=t-y;}
        }
    }
    void to_arr(char *c){
        char *c1=c;
        for (int i=0;i<len-1;++i)
            for (value x=a[i],b=base/10;b>=1;b/=10)*c1++='0'+x%10,x/=10;
        for (value x=a[len-1];x>0;x/=10)*c1++='0'+x%10;
        if (len==1&&a[len]==0)*c1++='0';
        if (sign==0)*c1++='-';*c1=0;reverse(c,c1);
    }
    void from_arr(char *c){
        size_t base_l=get_basel(),b=1;int cl=strlen(c);value x=0;
        New((cl+base_l-1)/base_l);len=0;
        if (*c=='-')sign=0,++c,--cl;else sign=1;
        while (--cl>=0){
            x+=(c[cl]-'0')*b;b*=10;if (b==base)a[len++]=x,x=0,b=1;
        }
        if (!len||x)a[len++]=x;
        while (len>1&&!a[len-1])--len;
    }
    void set_base(int _base){
        if (base==_base)return;
        char *c=new char[len*get_basel()+1];
        to_arr(c);base=_base;from_arr(c);
        delete[] c;
    }
    void set_basel(int _l){
        size_t _base=1;while (_l--)_base*=10;set_base(_base);
    }
    void read(){
        vector<char> s;char ch;
        scanf(" %c",&ch);if (ch=='-')s.push_back('-'),ch=getchar();
        for (;ch>='0'&&ch<='9';ch=getchar())s.push_back(ch);
        char *c=new char[s.size()+1];
        for (int i=0;i<s.size();++i)c[i]=s[i];c[s.size()]=0;
        from_arr(c);delete[] c;
        if (!*this)this->sign=1;
    }
    void print(){
        if (!sign)putchar('-');
        printf("%d",int(a[len-1]));
        for (int i=len-2;i>=0;--i){
            for (int j=base/10;j>=10;j/=10)
                if (a[i]<j)putchar('0');
                    else break;
            printf("%d",(int)a[i]);
        }
    }
    void println(){print();putchar('\n');}
    private:
    value *a,base;int len;bool sign;  //0="-"
    size_t get_basel()const{
        size_t res=0;for (int b=base/10;b>=1;b/=10,++res);
        return res;
    }
    #undef BASE
};

70分无高精做法

#include <bits/stdc++.h>
using namespace std;
#define int __int128
inline int read()
{
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
int bit[105];
inline void write(int x)
{
	if(x>9)write(x/10);
	putchar('0'+x%10);
}
signed main()
{
	freopen("rox.in","r",stdin);
	freopen("rox.out","w",stdout);
	int n=read();int ans=0;
	bit[0]=1;for(int i=1;i<=100;i++)bit[i]=bit[i-1]*2;
	for(int i=1;i<=n;i++)
	{
		if(bit[i-1]>n)break;
		int id=n%bit[i];
		int t=n/bit[i]+1,fi;
		if(id<=bit[i-1])fi=0;
		else fi=(id-bit[i-1])*2;
		int po=(bit[i-1])-1;int p;
		if(id>=po)p=(id-po)*2;
		else p=(po-id)*2;
		ans+=((t-1)*p+fi)*bit[i-1];
	}
	write(ans);puts("");
	return 0;
}

毕竟科学推理还是比无脑打表更胜一筹吧

T4.卡牌游戏

原题,又名《哪一天她能重回我身边》
数字当做点,把每张牌正面向背面连边,要求反向尽量少的边使得每个点出度最多是1
首先发现各个连通块互不影响,所以可以分别考虑
对于连通块,他的边数和点数有三种关系:
1\(m=n-1\)是一棵树,发现最优方案一定是选一个为根,然后所有点的边都指向他的父亲,所以可以树形dp
先随便选一个点当根算出这个点的答案,然后换根dp,\(g_y=g_x+1\),\(g_y=g_x-1\),具体看边的朝向
2.\(m=n\)基环树,环上断开做一遍,假设断掉\(x\)到\(y\)的边,那么答案就是\(\min(g_x,g_y+1)\)
3.\(m>n\)此时一定无解
放一个自家oj上带多测的

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
inline int read()
{	
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
const int N=200050;
struct node{
	int from,to,next,op;
}a[2*N];
int head[N],mm=2;
inline void add(int x,int y,int op)
{
	a[mm].from=x;a[mm].to=y;a[mm].op=op;
	a[mm].next=head[x];head[x]=mm++;
}
int p[N],m[N],tot,n,xx[N],yy[N],F[N];
vector <int> pp[N];bool flag,v[N];int cx,cy,bid;
void dfs(int x,int id)
{
	p[x]=id;pp[id].push_back(x);
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(p[y])continue;
		dfs(y,id);
	}
}
int f[N],g[N];
void dp1(int x,int fa)
{
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(y==fa)continue;
		dp1(y,x);
		f[x]+=f[y]+a[i].op;
	}
}
void dp2(int x,int fa)
{
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(y==fa)continue;
		if(a[i].op)g[y]=g[x]-1;
		else g[y]=g[x]+1;
		dp2(y,x);
	}	
}
void dp3(int x,int fa,int banid)
{
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(y==fa)continue;
		if(i==banid||i==(banid^1))continue;
		dp3(y,x,banid);
		f[x]+=f[y]+a[i].op;
	}
}
void dp4(int x,int fa,int banid) 
{
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(y==fa)continue;
		if(i==banid||i==(banid^1))continue;
		if(a[i].op)g[y]=g[x]-1;
		else g[y]=g[x]+1;
		dp4(y,x,banid);
	}	
}
void dfss(int x,int fa,int id)
{
	v[x]=1;
	for(int i=head[x];i;i=a[i].next)
	{
		int y=a[i].to;
		if(y==fa)continue;
		if(v[y])
		{
			cx=x;cy=y;bid=i;
			if(!a[i].op)swap(cx,cy);
			flag=1;return;	
		}
		F[y]=x;dfss(y,x,id);
		if(flag)return;
	}
}
inline void clear()
{
	memset(f,0,sizeof(f));memset(g,0,sizeof(g));memset(v,0,sizeof(v));
	memset(F,0,sizeof(F));memset(a,0,sizeof(a));memset(head,0,sizeof(head));mm=2;
	memset(p,0,sizeof(p));for(int i=1;i<=tot;i++)pp[i].clear(),m[i]=0;tot=0;
}
signed main()
{
	int T;cin>>T;
	while(T--)
	{
		clear();n=read();
		for(int i=1;i<=n;i++)
		{
			scanf("%lld%lld",&xx[i],&yy[i]);
			add(yy[i],xx[i],0);add(xx[i],yy[i],1);
		}
		for(int i=1;i<=2*n;i++)if(!p[i])dfs(i,++tot);
		for(int i=1;i<=n;i++)
		{
			int x=xx[i],y=yy[i];
			assert(p[x]==p[y]);
			m[p[x]]++;
		}
		bool die=0;int an1=0,an2=1;
		for(int i=1;i<=tot;i++)
		{
			if(!m[i])continue;int ma=n,ss=0;
			if(m[i]>pp[i].size()){die=1;break;}
			if(m[i]==pp[i].size()-1)
			{
				int root=pp[i][0];
				dp1(root,0);g[root]=f[root];assert(f[root]>=0);dp2(root,0);
				for(int j=0;j<pp[i].size();j++)ma=min(ma,g[pp[i][j]]);
				for(int j=0;j<pp[i].size();j++)if(g[pp[i][j]]==ma)ss++;
			}
			else
			{
				if(pp[i].size()==1)continue;
				dfss(pp[i][0],0,i);flag=0;
				dp3(cx,0,bid);g[cx]=f[cx];dp4(cx,0,bid);
				ma=min(g[cx],g[cy]+1);
				if(g[cx]==g[cy]+1)ss=2;
				else ss=1;
			}			
			assert(ma>=0);
			an1+=ma;an2=an2*ss%mod;
		}	
		if(die)puts("-1 -1");
		else printf("%lld %lld\n",an1,an2);
	}
	return 0;
}

考试总结

发现还是没有进步,依然不能让理性支配头脑,思维可到但细节不到,容易在T2T3崩盘
现在发现自己其实没有策略,只是在按照以为能打好的方向打,CSP的时候也是这样,只不过当时撞大运没崩
不会签到题,不会原题,不能正确认识自己的代码能力,又因为细节把少的可怜的分挂没
没有如果,唯一庆幸的这不是联赛,还有六天,该好好想想了

标签:return,int,res,len,Int,base,模拟,编号,考试
来源: https://www.cnblogs.com/PMZG/p/15549924.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有