zoukankan      html  css  js  c++  java
  • 9.17 考试

    (首先喷一下出题人 这题真优(du)美(liu))

    t1

    题意 :

    n*m矩阵 每个数\([1,12]\) , 给你两个操作, 可以执行任意多次

    <1> 对某一行 ,所有数字加1;

    <2> 对某一列 , 所有数字加1;

           如果执行完上述操作之后,矩阵中某个数变成了3,6,9,12其中的某一个,我们认为这个数是稳的。
    
         给定初始矩阵,求出任意执行操作之后稳数的最多个数
    

    \(n,m<=5\)

    思路:

    首先想到爆搜 emmm, 然额 不知道搜啥
    摆性质: 存在一种最优方案,使得在每一行每一列加上的数都不超过2
    证明 : 假设一个操作使某一行或某一列加上了x且x大于2,则如果让x减去3,则x仍然是非负整数,这一行(列)内3的倍数的个数没有变,并且小于等于12的数的个数会不变或更多。这样我们就证明了当x≥3时某一行(列)加上\(x-3\)不会比加上x更劣。
    蓝后就有思路了;
    先枚举每一行 加多少\((0,2)\), 再枚举计算每一列加多少\((0,2)\), 最后按列统计答案 ;

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <iostream>
    #define N 1000005
    #define inf 1e9
    #define LL long long
    #define qwq  cout<<"!!!!!"<<endl;
    using namespace std;
    int read()
    {
    	int x=0,f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f*x;
    }
    int xx, yy, ans=-23333,n, m, a[20][20], md[20];
    int zz[20][3];//第 i 列有多少个% 3 ==k 
    
    int check(int x)
    {
    	return (x%3==0&&x<=12);
    }
    void dfs(int cnt)
    {
    	if(cnt==n + 1) {
    		int res = 0;
    		for (int j = 1; j <= m; j++) {
    			zz[j][0]=zz[j][1]=zz[j][2]=0;
    			for(int i = 1; i <= n; i ++)
    			for(int k = 0; k <= 2; k ++)
    			zz[j][k] += check(a[i][j] + md[i] + k);
    			res += max(max(zz[j][0],zz[j][1]), zz[j][2]);	
    		}
    		ans = max(res, ans);
    		return ;
    	}
    	for(int i = 0; i <= 2; i++)
    	 md[cnt] = i, dfs(cnt + 1);
    }
    signed main()
    {
        freopen("zzx.in","r",stdin);
        freopen("zzx.out","w",stdout);
        n = read();
        m = read();
        for(int i = 1; i <= n; i ++)
           for(int j = 1; j <= m; j ++)
              a[i][j] = read();
        dfs(1);
          	printf("%d ",ans);
    	return 0;
    }
    

    T2.

    题面:

    【题目描述】

       给定一个长度为偶数的排列p,你每次可以选取p排列中相邻的两个元素,假如分别是x和y,那么把x和y加入一个序列q的末尾,并将x和y从排列p中删除。重复上述过程,直到p中没有元素,显然最终q序列也是一个排列。例如$p=(1,3,2,4)$,第一次可以选取3,2这两个元素加入q,并且从p中删除,此时$p=(1,4)$,第二次可以选取1,4这两个元素加入q,此时p为空,$q=(3,2,1,4)$。观察上述过程,最终q序列可能会有很多方案,请你输出所有可能方案中,q的字典序最大的。
    

    字典序的比较方式如下,假设有两个长度同为n的序列a,b。我们找到最大的t,使得\(∀i≤t,a[i]=b[i]\)。之后比较\(a[t+1]\)\(b[t+1]\),如果\(a[t+1]<b[t+1]\),我们就认为a的字典序比b小,反之亦然。

    【输入格式】

    第一行包含一个正整数 n。第二行 n 个数,表示排列 p。

    【输出格式】

    一行 n 个数,表示字典序最大的序列 q。

    【输入样例1】

    4

    3 1 4 2

    【输出样例1】

    4 2 3 1

    【输入样例2】

    6

    6 5 4 1 3 2

    【输出样例2】

    6 5 4 1 3 2

    【数据规模及约定】

    对于20%的数据,n≤10。

    对于60%的数据,n≤1,000。

    对于100%的数据,n≤100,000。

    思路:

    貌似看上去很简单,然而发现并不是这样%%Theaker
    

    就是每次找一个最大值 x 和一个次大值 y

         如果x是当前最后一个元素, 就把y和y的下一个元素取出;
    
          否则 把y和y的下一个元素取出
    

    重点是咋维护呢?(链表连起来)

    然后你就会有体会到 数组套数组 套了三四层(真kongbu, 感觉度数会长100度。。。)

    像这样

    a[a[a[ a[t.id].nxt].nxt]].val
    

    然后就出现了指针选手(指针大发真的吼)

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <queue>
    #define N 100005
    #define inf 1e9
    #define LL long long
    #define qwq  cout<<"!!!!!"<<endl;
    using namespace std;
    const int N = 100010;
    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 << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    struct node
    {
    	int val , vis;
    	node *nxt , *fa;
    	node () {val = vis = 0;nxt = fa = NULL;}
    }*root;
    struct num
    {
    	int val;
    	node *p;
    	friend bool operator < (const num & a,const num & b) { return a.val < b.val;}
    };
    int n , cnt;
    priority_queue<num>q;
    int main()
    {
    	freopen("ysy.in","r",stdin);
    	freopen("ysy.out","w",stdout);
    	n = read();
    	node *p = root = new node();
    	for(int i = 1;i <= n;i ++)
    	{
    		p -> val = read();
    		q.push((num){p -> val,p});
    		if(i < n)
    		{
    			p -> nxt = new node();
    			p -> nxt -> fa = p;
    			p = p -> nxt;
    		} 
    	}
    	while(cnt != (n >> 1))
    	{
    		node *p = q.top().p;
    		q.pop();
    		if(p -> nxt == NULL) continue;
    		if(p -> vis || p -> nxt -> vis) continue;
    		printf("%d %d ",p -> val,p -> nxt -> val);
    		cnt ++;
    		if(p -> fa && p -> nxt && p -> nxt -> nxt)
    		{
    			p -> nxt -> nxt -> fa = p -> fa;
    			p -> fa -> nxt = p -> nxt -> nxt;
    		} 
    		p -> vis = 1;
    		p -> nxt -> vis = 1;
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    毒瘤T3

    题意:

    没有什么能够阻挡,你对被阿的向往。天天AK的生涯,你的心了无牵挂。

    虐过大佬的比赛,也曾装弱装逼。当你低头的瞬间,才发现旁边的人。

    把你的四肢抬起来,使劲地往门上撞。盛开着永不凋零,黑莲花。

                ——《黑莲花》
    

    给你一个数列, 两个操作 :
    1 l r x:表示区间\([l,r]\)加上x。
    2 l r p:询问
    的值。

    思路:

    ( 机房巨佬全用的树状数组, 就本蒟蒻在傻傻的分块 )

    1、对于第一个操作, 显然乱七八糟的数据结构的是随便套的 ;
    2、这就贼恶心了,
    显然要暴力搞
    话说考场上, 半个小时的时间, 一直在\(mod p\), (真是傻到家了)
    蓝后就想起来这不是\(a^bmod p\) 嘛, 不会是 \(phi(p)\) 吧(没错就是它)
    改一下, 震惊! 过样例了。。。再套上扩展欧拉定理, 对就这样(然后就过了两个点)

    正解思路:

    首先这是一道数据结构+数论的好(duliu)题。
    


    而对于询问区间\([l,r] mod p\)(其询问结果记作\(s(l,r,p)\)),有:

    (假设上式中出现的模p意义下的幂指数都大于等于\(φ(p)\)

    然后你会发现
    (然而我在考试时推到上一步了 ,并没有发现发现啥)
    (啊。还是我太弱了)
    将 p 不断变 \(phi(p)\)只需, \(logp\) 次就变成 1 , 指数为1, 就可以直接算;
    所以对于递归\((l, r, p)\)
    1、\(l==r\) \(or\) \(p==1\) 直接返回\(a[l]\) ;
    2、否则递归到\(s(l+1,r,φ(p))\),记其为\(t\), 如果\(t≥φ(p)\)则返回\(a[l]^{tmodφ(p) + φ(p)}\) , 否则返回
    \(a[l]^{t}\)

    然后就有一个新的问题 : 递归怎么判断指数大小.......由于 \(p<=2* 10^7\) , \(2^{2^{2^{2^{2}}}}>2*10^7\)
    所以,我们只需要取出\([l+1,r]\)的前5个数(如果\([l+1,r]\)的区间长度不足5则取区间\([l+1,r]\)内所有数,如果\([l+1,r]\)内第一个1出现的位置为x则取\([l+1,x-1]\)内所有数)
    如果取出的数的个数为5则一定大于\(φ(p)\)。否则可以大力快速幂判断指数是否大于等于\(φ(p)\)
    可以用线性的欧拉筛预处理欧拉函数。
    虽然出题人把时间开到9s, 但我并不觉得他很liangxin

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <iostream>
    #include <cmath>
    #define N 500005
    #define int long long
    #define  LL long long
    #define qwq  cout<<"!!!!!"<<endl;
    const int maxx = 2e7+5;
    using namespace std;
    int read()
    {
    	int x=0,f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n, m, a[N];
    int len, pos[N], ll[N], rr[N], num, add[N];
    int opt, xx, yy, zz, flag;
    int phi[maxx], vis[maxx], prime[maxx], cnt;
    void yych() 
    {
    	len = sqrt(n);
    	num = n/len; if(n%len != 0)num++;
    	for(int i = 1; i <= n; i++)
    	  pos[i] = (i-1)/len +1;
    	for(int i = 1; i <= num; i++) {
    		ll[i] = (i-1)*len +1;
    		rr[i] = i*len;
    	}rr[num] = n;
    }
    void chenge(int l, int r, int x) 
    {
    	if(pos[l]==pos[r])
    	{
    		for(int i = l; i <= r; i ++)
    		 a[i] +=x;
    		 return;
    	}
    	for(int i = l; i <= rr[pos[l]]; i++)
    	 a[i] += x;
    	for(int i = pos[l]+1; i <= pos[r]-1; i++)
    	 add[i] += x;
    	for(int i = ll[pos[r]]; i <= r; i++)
    	 a[i] += x;
    }
    int power(int x, int y, int p)
    {
        int ans = 1;
        if(x >= p) flag = 1, x %= p;
        while(y)
        {
        	if(y&1) ans = ans * x;
        	x = x * x;
        	if(x >= p) flag = 1, x %= p;
        	y >>= 1;
        	if(ans >= p) flag = 1, ans %= p;
        }
    	return ans;
    }
    void zh_dou()
    {
    	phi[1]=1;
    	for(int i=2;i<=20000008;i++)
    	{
    		if(!vis[i])
    		{
    			prime[++cnt]=i;
    			phi[i]=i-1;
    		}
    		for(int j=1;j<=cnt&&prime[j]*i<=20000008;j++)
    		{
    			vis[prime[j]*i]=1;
    			if(i%prime[j]==0)
    			{
    				phi[i*prime[j]]=phi[i]*prime[j];
    				break;
    			}
    			phi[i*prime[j]]=phi[i]*(prime[j]-1);
    		}
    	}
    }
    int ask(int l, int r, int p)
    {
    	if(l == r|| p == 1) 
    		return  (a[l]+add[pos[l]]);
        int t = ask(l + 1, r, phi[p]);
        if(t > p ||flag ) t = t%phi[p] + phi[p], flag = 0;
    	return power(a[l]+add[pos[l]], t, p); 
    }
    signed main()
    {
        freopen("zzq.in","r",stdin);
        freopen("zzq.out","w",stdout);
        n = read();
        m = read();
        for(int i = 1; i <= n; i++)
           a[i] = read();
         yych();
         zh_dou();
         while(m--) 
    	 {
         	opt = read();xx = read(); yy = read(); zz = read();
         	if(opt == 1) 	
         	     chenge(xx, yy, zz);
         	else  
         	     flag = 0,//每次都要赋0,(会挂)
    			 printf("%lld\n", ask(xx, yy, zz)%zz);
         }
    	return 0;
    }
  • 相关阅读:
    html分页自适应居中;css设置分页自适应居中
    jQuery如何给DOM添加ID
    jquery如何获取div下ul的某个li
    js正则验证数字的方法
    css改变input输入框placeholder值颜色
    js校验表单后提交表单的三种方法总结
    Thinkcmf子栏目获取父级栏目所有子栏目列表
    Thinkcmf截取内容长度
    thinkcmf2.2 火狐浏览器图片上传以及谷歌图片上传打开稍慢
    c语言结构体中的冒号的用法
  • 原文地址:https://www.cnblogs.com/spbv587/p/11536415.html
Copyright © 2011-2022 走看看