zoukankan      html  css  js  c++  java
  • Test1016

    T1 kom (容斥

    ((1s32M))

    给出(N)个互不相同的正整数,统计共有多少对数,它们有公共的一个数字(不一定在同一位置上)

    输入

    第一行一个正整数 (N (1 ≤ N ≤ 1 000 000)).
    接下来(N)行,每行一个正整数([1, 10^{18}]),

    输出

    一个数,表示满足条件的对数

    input

    3
    4
    20
    44
    
    

    output

    1
    
    

    input

    4
    32
    51
    123
    282
    
    
    

    output

    4
    
    

     
     
     

    暴力((18*n^2))

    枚举两个数逐位判断

    容斥((1024*1024))

    发现我们只在乎有哪些数字出现过,就可以只存每个数中那些数码出现过,这样内存需要((1e6*10)),发现被卡内存了,那我们可以用二进制转换一下,二进制数中第(i)位代表这个数中(i)出现过,这样每个数都可以转化成一个(10)位二进制数最大是(1023);

    这下就可以用桶统计每种数有多少个(这里的种类是指出现的数码集合相同),但题目只要求一个数码相同,所以对于每个数码进行统计会重复,自然想到了容斥;

    枚举一个状态(i(i<1024)),对于一类数(j)((isubset j)具体体现就是(j|i=j)),所有的(j)都包含(i)这个状态,假设有(num)个,对答案的贡献是(num*(num-1)/2),容斥系数就是二进制下(i)(1)的数量;

    枚举替代容斥((1024*1024))

    因为状态很少,我们可以省略容斥,可以直接枚举两个状态((i,j)),如果有交集((i&j!=0)),(ans+=num[i]*num[j])

    #include<bits/stdc++.h> 
    #define ll long long  
    using namespace std; 
    const int N=1000005;
    int n;
    int a[2050];
    int x;
    ll ans;
    inline int read()
    {
    	int x=0,f=1;char st=getchar();
    	while(st<'0'||st>'9'){if(st=='-') f=-1;st=getchar();}
    	while(st>='0'&&st<='9') x=x*10+st-'0',st=getchar();
    	return x*f;
    }
    
    int main()
    {
    	freopen("kom.in","r",stdin);
    	freopen("kom.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		x=0;char c=getchar();
    		while(c<'0'||c>'9')c=getchar();
    		while(c>='0'&&c<='9') x|=(1<<(c-'0')),c=getchar();
    		a[x]++;
    	}
    		
    	for(int i=1;i<1024;i++)
    	{
    		int num=0,num1=0;
    		for(int j=1;j<1024;j++)if((j|i)==j) num+=a[j];
    		for(int j=0;j<10;j++) if((i>>j)&1) num1++;
    		if(num1&1)
    		{
    			ans+=(ll)num*(num-1)/2;
    		}
    			
    		else 
    		{
    			ans-=(ll)num*(num-1)/2;
    		}
    			
    	}
    	
    		
    	printf("%lld",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    T2 fun (记搜

    ((1s128M))

    给出一程序(函数),输出程序运行后的结果。程序如下:

    C++代码:

    int fun() {  
    int ret = 0;   
    for (int a = X1; a <= Y1; ++a)
    for (int b = X2; b <= Y2; ++b)
    ...
    for (int <N-th> = XN; <N-th> <= YN; ++<N-th>)
    ret = (ret + 1) % 1000000007;
    return ret;
    }
    

    (<N-th>)表示字母表中每(N)个字母,$Xi (和)Yi$表示小于等于(100000)的正整数,或者表示一个循环变量(前面的)。

    比如:(X3)可以为 (a),$ b(,或者一个正整数。每一行的)Xi and Yi$至少有一个是数。

    输入

    第一行一个正整数 (N (1 ≤ N ≤ 26)).
    接下来(N)行,每行两个用空格隔开的量 (Xi and Yi),如果两个都是数字,则(Xi ≤ Yi).

    输出

    一个数字,表示程序的输出结果

    2
    1 2
    a 3
    
    

    output

    5
    

    input

    3
    2 3
    1 2
    1 a
    
    
    

    output

    10
    
    
    

    input

    3
    1 2
    a 3
    1 b
    
    

    output

    11
    
    

     
     
     

    蛮恶心的一道题;

    就是让你数循环次数;但是有复杂的嵌套结构;

    对于每一对依赖关系连一条边,我们可以得到很多树(森林),(因为每一层最多连一条边),这样的话只有父节点的取值会影响当前节点的循环次数;

    我们可以在此基础上记搜;

    我们发现只有根节点的左右边界都是数;

    对于一个节点,在当前取值下的循环次数应是在当前取值下子节点的循环次数的,因为子节点总是有先后顺序的;

    那记什么呢?我们发现当前节点会对同一边界情况搜很多次,我们记录一个(f[i][j])代表(i)号节点,其父节点的取值是(j)的循环次数,其中(j)是左边界还是右边界是由节点自身情况决定的;

    假如j是左边界可以得到

    [f[i][j]=sum_{o=j}^{r}prod{dfs(k,o)} ]

    (k)是当前节点的一个子节点,(dfs(k,o))是搜第(k)层,其父亲取值是(o)的情况;

    这里为什么又是加呢,很显然每个节点不同取值之间是没有影响的;

    这样子可以的(80);

    我们还可以考虑一下继承,假设我们的取值都是从小到大枚举的,那我们算取值是(i)时,(i-1)的情况已经算过了;

    如果(i)是左边界,那(i-1)的情况比(i)多算了取值为(i-1)的影响,将这部分减去就可以了

    如果(i)是右边界,那(i-1)的情况比(i)少算了取值为(i)的影响,将这部分加上就可以了

    #include<bits/stdc++.h> 
    #define ll long long 
    using namespace std; 
    const int mod=1000000007;
    int n;
    char ca[30],cb[30];
    int a[30],b[30];
    ll ans=1;
    ll f[30][100005];
    struct skr
    {
    	int to,nxt;
    }t[30];
    int head[30],cnt;
    inline int read()
    {
    	int x=0,f=1;char st=getchar();
    	while(st<'0'||st>'9'){if(st=='-') f=-1;st=getchar();}
    	while(st>='0'&&st<='9') x=x*10+st-'0',st=getchar();
    	return x*f;
    }
    
    inline void add(int x,int y)
    {
    	t[++cnt].to=y;t[cnt].nxt=head[x];head[x]=cnt;
    }
    
    inline ll dfs(int x,int l)
    {
    	if(~f[x][l]) return f[x][l];
    	f[x][l]=0;
    	if(!a[x])
    	{
    		f[x][l]=0;
    		ll res=1;
    		if(l>b[x])return f[x][l]=0;
    		if(~f[x][l-1])
    		{
    			res=1;
    			for(int k=head[x];k;k=t[k].nxt)
    			{
    				res=(res*dfs(t[k].to,l-1))%mod;
    			}
    			f[x][l]=(f[x][l-1]-res+mod)%mod;
    		}
    		else 
    		{
    			for(int i=l;i<=b[x];i++)
    			{
    				res=1;
    				for(int k=head[x];k;k=t[k].nxt)
    				{
    					res=(res*dfs(t[k].to,i))%mod;
    				}
    				f[x][l]=(f[x][l]+res)%mod;
    			}
    		}
    			
    			
    	}
    	else
    	{
    		f[x][l]=0;
    		ll res=1;
    		if(a[x]>l)return f[x][l]=0;
    		if(~f[x][l-1])
    		{
    			res=1;
    			for(int k=head[x];k;k=t[k].nxt)
    			{
    				res=(res*dfs(t[k].to,l))%mod;
    			}
    			f[x][l]=(f[x][l-1]+res)%mod;
    		}
    		else
    		{
    			for(int i=a[x];i<=l;i++)
    			{
    				res=1;
    				for(int k=head[x];k;k=t[k].nxt)
    				{
    					res=(res*dfs(t[k].to,i))%mod;
    				}
    				f[x][l]=(f[x][l]+res)%mod;
    			}
    		}
    			
    	}
    	return f[x][l];
    }
    
    int main()
    {
    	freopen("fun.in","r",stdin);
    	freopen("fun.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		int x=0;
    		char c=getchar();
    		while((!('a'<=c&&c<='z'))&&(!('0'<=c&&c<='9'))) c=getchar();
    		if('a'<=c&&c<='z') 
    		{
    			ca[i]=c;
    			add(c-'a'+1,i);
    		}
    		else
    		{
    			while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    			a[i]=x;
    		}
    		x=0;c=getchar();
    		while((!('a'<=c&&c<='z'))&&(!('0'<=c&&c<='9'))) c=getchar();
    		if('a'<=c&&c<='z') 
    		{
    			cb[i]=c;
    			add(c-'a'+1,i);
    		}
    		else
    		{
    			while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    			b[i]=x;
    		}
    	}
    	memset(f,-1,sizeof f);
    	for(int i=1;i<=n;i++)
    	if(a[i]&&b[i])
    	{
    		f[i][0]=0;
    		for(int j=a[i];j<=b[i];j++)
    		{
    			ll res=1;
    			for(int k=head[i];k;k=t[k].nxt)
    				res=(res*dfs(t[k].to,j))%mod;
    			f[i][0]=(f[i][0]+res)%mod;
    		}
    		ans=(ans*f[i][0])%mod;
    	}
    	printf("%lld",ans);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    T3 ras (权值线段树

    ((1.5s128M))

    给定(N)个订单,每个订单用两个数字表示,一个表示订单交货时间,一个表示产品制作需要的时间,一个订单完成后(送货时间不计),就可收到小费,如果比规定时间提前(K)个时间,则可获得(K),注意准时送到得(0),迟送到就得对应的负值。(也就是订单上的时间减提交的时间),开始生产的时间为(0),请合理安排订单的顺序,以获得最大的小费,输出小费值。(第一问)

    另外,给定(C)个修改,每个修改,改变一个订单,对于每次修改输出改后所有订单能得的最大小费数。

    输入

    第一行两个正整数N and C,表示订单数,和订单修改的次数.
    接下来N行,每行两个数(Li,Ti)分别表示订单提交时间和订单制作时间。
    接下来C行,每行三个数(R,L,T),依次原订单的编号,提交时间,制作时间。

    Constraints:  
    1 ≤ N, C ≤ 200 000,
    0 ≤ Li, L ≤ 100 000,
    1 ≤ Ti, T ≤ 100 000,
    1 ≤ R ≤ N.
    
    

    输出

    第一行一个数,表示最开始能获得的最大小费。
    接下来C行,每行一个数,表示修改这个订单后能获得的最大小费。

    input

    3 2
    10 2
    6 5
    4 3
    1 6 1
    3 0 10
    

    output

    3
    2
    -11
    

    input

    4 2
    3 2
    0 3
    4 3
    4 1
    3 0 4
    1 4 5
    

    output

    -8
    -13
    -18
    

    input

    6 7
    17 5
    26 4
    5 5
    12 4
    8 1
    18 2
    3 31 3
    4 11 5
    4 19 3
    5 23 2
    6 15 1
    5 19 1
    3 10 4
    

    output

    27
    59
    56
    69
    78
    81
    82
    58
    

    对于第一个例子,原始订单完成的顺序((1, 3, 2)). 第一个订单完成时 (t = 2),第三个(t = 5),第二个 (t = 10).所以第一个订单可获(8)个小费,第二个获(-1),第(3)个获(-4))所以总数为(3).
    第一次改变后,订单完成顺序不变,得小费为 (5, 0, and -3),第二次改变后,最优顺序为((1, 2, 3)), 小费为 (5),(0),$ and$ (-16)

     
     
     

    每一个订单对答案的贡献是“截止时间-实际制作时间”,将每一个实际制作时间拆开,发现每一个订单的制作时间的影响是时间乘它后面的订单数+自己;

    那么答案可以写成

    [sum{l-t*(n-i+1)} ]

    我们将截止时间单独统计,将制作时间由小到大排序,以这样的顺序制作是最优的,因为这样让等待时间降至最小;

     
     

    但问题涉及到了修改订单,我们考虑当前状态与上一个状态的差值;

    修改一个点其实相当于把原值删掉再加入一个新值;

    其实删除与加入是完全相反的,我们只讨论删除;

    由于涉及到大小顺序,我们可以维护一个权值线段树(权值树状数组)

    维护当前节点出现的次数和出现这么多次的总和,线段树分别维护两个值得和;

    当删除某个订单时,先将它的(l)删去;

    再删除某个值(t)时,先将对应值出现次数(-1),对应值的总和(-t)

    再考虑少减了多少,

    首先是它自己没有了,它原本的贡献是(t*(n-i+1))

    我们区间查询出有多少个比(t)小,假设是(g)个,答案应当加上(t*(n-g))

    其次是对其他值的影响,现在(n)变成了(n-1),而比(t)大的部分排名也减少了(1),所以这部分没有变,但比(t)小的就会少减一次,所以答案应该加上比(t)少了的元素的和

    添加相反

     
     

    #include<bits/stdc++.h> 
    #define ll long long
    #define ls p<<1
    #define rs p<<1|1
    #define l(p) a[p].l
    #define r(p) a[p].r
    using namespace std;
    
    const int N=200005;
    
    int n,zc[N],num[N],c;
    ll tot;
    struct book
    {
    	int l,t;
    }b[N];
    struct ST
    {
    	ll sum;
    	int dat;
    	int l,r;
    }a[N<<1];
    inline bool cmp(ll x,ll y)
    {
    	return b[x].t<b[y].t;
    }
    
    inline int read()
    {
    	int x=0,f=1;char st=getchar();
    	while(st<'0'||st>'9'){if(st=='-') f=-1;st=getchar();}
    	while(st>='0'&&st<='9') x=x*10+st-'0',st=getchar();
    	return x*f;
    }
    
    inline void update(int p)
    {
    	a[p].dat=a[ls].dat+a[rs].dat;
    	a[p].sum=a[ls].sum+a[rs].sum;
    }
    
    inline void build(int p,int l,int r)
    {
    	l(p)=l;r(p)=r;
    	if(l==r)
    	{
    		a[p].dat=num[l];
    		a[p].sum=num[l]*l;
    		return ;
    	}
    	int mid=l+r>>1;
    	build(ls,l,mid);
    	build(rs,mid+1,r);
    	update(p);
    }
    inline void change(int p,int d,int x)
    {
    	if(l(p)==r(p))
    	{
    		a[p].dat+=x;
    		a[p].sum+=(ll)x*l(p);
    		return ;
    	}
    	int mid=l(p)+r(p)>>1;
    	if(d<=mid) change(ls,d,x);
    	else change(rs,d,x);
    	update(p);
    }
    
    inline ll ask(int p,int l,int r)
    {
    	if(l(p)>=l&&r(p)<=r) return a[p].sum;
    	int mid=l(p)+r(p)>>1;
    	ll val=0;
    	if(l<=mid) val+=ask(ls,l,r);
    	if(r>mid) val+=ask(rs,l,r);
    	return val;
    }
    
    inline int asknum(int p,int l,int r)
    {
    	if(l(p)>=l&&r(p)<=r) return a[p].dat;
    	int mid=l(p)+r(p)>>1;
    	int val=0;
    	if(l<=mid) val+=asknum(ls,l,r);
    	if(r>mid) val+=asknum(rs,l,r);
    	return val;
    }
    int main()
    {
    	freopen("ras.in","r",stdin);
    	freopen("ras.out","w",stdout);
    	n=read();c=read();
    	for(int i=1;i<=n;i++)
    	{
    		b[i].l=read();b[i].t=read();
    		tot+=b[i].l,zc[i]=b[i].t;
    		num[b[i].t]++;
    	}
    	sort(zc+1,zc+1+n);
    	build(1,1,100000);
    	for(int i=1;i<=n;i++)
    		tot-=(ll)zc[i]*(n-i+1);
    	printf("%lld
    ",tot);
    	for(int i=1;i<=c;i++)
    	{
    		int r=read(),l=read(),t=read();
    		
    		tot-=b[r].l;
    		change(1,b[r].t,-1);
    		tot+=ask(1,1,b[r].t-1);
    		int g=asknum(1,1,b[r].t-1);
    		tot+=(ll)(n-g)*b[r].t;
    		
    		b[r].l=l;b[r].t=t;
    		tot+=l;
    		
    		change(1,b[r].t,1);
    		tot-=ask(1,1,b[r].t-1);
    		g=asknum(1,1,b[r].t-1);
    		tot-=(ll)(n-g)*b[r].t;
    		
    		printf("%lld
    ",tot);
    	}
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }                                    
    
  • 相关阅读:
    vue----计算与监听属性
    vue---条件与循环语句
    vue--模板语法
    git版本控制系统--介绍
    HttpWebRequest使用总结
    计算机专业的书普遍都这么贵,你们都是怎么获取资源的?
    130 个相见恨晚的超实用网站,一次性分享出来
    实现客户端与服务端的HTTP通讯
    默认网关(地址)
    .NET Reactor使用教程(加密源代码示例)
  • 原文地址:https://www.cnblogs.com/yudes/p/12012266.html
Copyright © 2011-2022 走看看