• 2020-11-09至11-15周任务 看 法


    写在前面

    对于这个机制提出的建议:

    • 题目偏多,偏杂。建议取消硬性规定题目,这种大规模刷题应该放在平时,而不是放在NOIP这种大考前,考前主要是找自己薄弱点

    • 每周写博客的机制可以保留,不一定大家都要写一样的一套题目,毕竟每个人都有自己的薄弱处,可以刻意刷一些自己不熟练的题目,然后每周写成博客,方便参考

    题解

    A(模拟)

    大模拟,儒略日100一轮回来取模,1852年特殊处理一下,1853年之后400年一轮回取模

    之前写了一个400 + 100 + 4 的奇怪轮回,但是后面100与4的轮回完全没必要,反而增加了代码难度

    tips:在能过的前提下,代码越简单越好

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    int JLtotDays = 0;
    int T, Year, Month, Day, Res1582;
    int Year400tot, Year100tot, Year18tot; // common
    int month[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline int read () {
    	int tot = 0, f = 1; char c = getchar ();
    	while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar (); }
    	while (c >= '0' && c <= '9') { tot = tot * 10 + c - '0'; c = getchar (); }
    	return tot * f;
    }
    signed main () {
    //	freopen ("P7075_6.in", "r", stdin);
    //	freopen ("julian.out", "w", stdout); 
    	for (int i = -4712; i < 1582; i++) {
    		JLtotDays += 365;
    		if (i % 4 == 0) JLtotDays++;
    	}
    	for (int i = 1; i < 10; i++) JLtotDays += month[i]; JLtotDays += 4;
    	Res1582 = 31-15 + month[11] + month[12];
    	for (int i = 1583; i < 1983; i++) {
    		Year400tot += 365;
    		if (i % 4 == 0 && i % 100 != 0) Year400tot++;
    		else if (i % 400 == 0) Year400tot++;
    	}
    	for (int i = 1583; i < 1683; i++) {
    		Year100tot += 365;
    		if (i % 4 == 0 && i % 100 != 0) Year100tot++;
    	} // 预处理
    	for (int i = 1583; i <= 1600; i++) {
    		Year18tot += 365;
    		if (i % 4 == 0 && i % 100 != 0) Year18tot++;
    	}
    //	cout<<JLtotDays<<" "<<Res1582<<endl;
    	T = read ();
    	while (T--) {
    		month[2] = 28;
    		Day = read (); Day++;
    		if (Day == 2299162) { // 特判
    			printf ("15 10 1582
    ");
    			continue;
    		}
    		if (Day <= JLtotDays) { // 儒略日
    			Year = -4712;
    			if (Day > 4 * 365 + 1) {
    				Year += 4 * (Day / (4 * 365 + 1));
    				Day %= (4 * 365 + 1);
    				if (Day == 0) Day += (4 * 365 + 1), Year -= 4;
    			}
    //			cout<<Year<<endl;
    			bool flag = 0;
    			if (Day > 366) Year++, Day -= 366, flag = 1;
    			if (Day > 365 && flag) Year += (Day / 365), Day %= 365;
    			if (Day == 0) Day += 365, Year--;
    			if (Year % 4 == 0) month[2] = 29;
    			for (Month = 1; Day > month[Month]; Month++) Day -= month[Month];
    			printf ("%d %d ", Day, Month);
    			if (Year <= 0) {
    				printf ("%d BC
    ", -Year + 1);
    			}
    			else printf ("%d
    ", Year);
    		}
    		else { Day -= JLtotDays; // 格里高利历
    			if (Day <= Res1582) {
    				if (Day <= 31 - 15)
    					printf ("%d 10 1582
    ", Day + 15);
    				else if (Day <= 31 - 15 + month[11])
    					printf ("%d 11 1582
    ", Day - (31 - 15));
    				else printf ("%d 12 1582
    ", Day -(31 - 15 + month[11]));
    			}
    			else {
    				Day -= Res1582;
    				Year = 1583;
    				if (Day > Year400tot) {
    					Year += 400 * (Day / Year400tot);
    					Day %= Year400tot;
    					if (Day == 0) Year -= 400, Day += Year400tot;
    				}
    				bool flag = 0, tag = 0;
    				if (Day > Year100tot + 1)
    					Day -= Year100tot + 1, Year += 100, flag = 1;
    				if (Day > Year100tot && flag) {
    					Year += 100 * (Day / Year100tot), Day %= Year100tot;
    					if (Day == 0) Year -= 100, Day += Year100tot;
    				}
    //				cout<<Day<<" "<<Year<<" "<<Year18tot<<endl;
    				if (Day > Year18tot) {
    					if ((Year + 17) % 400 == 0 ) {
    						if (Day > Year18tot + 1) Day -= Year18tot + 1, Year += 18, tag = 1;
    					}
    					else Day -= Year18tot, Year += 18; tag = 1;
    				}
    //				cout<<Day<<" "<<Year<<" "<<tag<<endl;
    				if (Day > (4 * 365 + 1)) {
    					Year += 4 * (Day / (4 * 365 + 1));
    					Day %= (4 * 365 + 1);
    					if (Day == 0) Year -= 4, Day += 4 * 365 + 1;
    				}
    //				cout<<Day<<" "<<Year<<" "<<tag<<endl;
    				if (!tag) {
    					flag = 0;
    					if (Day > 365) Year ++, Day -= 365;
    					if (Day > 366) Year ++, Day -= 366, flag = 1;
    					if (Day > 365 && flag) Year ++, Day -= 365;
    				}
    				else if (Day > 365) {
    					int t = 365; if ((Year % 4 == 0 && Year % 100 != 0) || Year % 400 == 0) t++;
    					while (Day > t) {
    						Day -= t; Year ++;
    						t = 365;
    						if ((Year % 4 == 0 && Year % 100 != 0) || Year % 400 == 0) t++;
    					}
    				}
    //				cout<<Day<<endl;
    				if ((Year % 4 == 0 && Year % 100 != 0) || Year % 400 == 0) month[2] = 29;
    				for (Month = 1; Day > month[Month] && Month < 12; Month++) Day -= month[Month];
    				/*if (Day == 0 && Month == 1) {
    					Month = 12, Year--, Day = 31;
    					if ((Year % 4 == 0 && Year % 100 != 0) || Year % 400 == 0) Day = 30;
    				}*/
    //				if (Day == 1 && Month == 1 && (((Year - 1) % 4 == 0 && (Year - 1) % 100 != 0) || (Year - 1) % 400 == 0)) Day = 31, Month = 12, Year--;
    				printf ("%d %d %d
    ", Day, Month, Year);
    			}
    		}
    	}
    	return 0;
    }
    

    B(位运算)

    把所有给出的动物全部或起来,这样就得到了一个包含所有初始动物所需的饲料的序列,之后直接算一下就得出答案了

    注意:会爆ull,可以分两次加,先一次,再减去个n,之后再加

    #include <bits/stdc++.h>
    #define int unsigned long long
    using namespace std;
    const int K = 65;
    int n, m, k, c, a, q, p;
    bool v[K];
    int s;
    inline int read () {
    	int tot = 0, f = 1; char c = getchar ();
    	while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar (); }
    	while (c >= '0' && c <= '9') { tot = tot * 10 + c - '0'; c = getchar (); }
    	return tot * f;
    }
    signed main () {
    //	freopen ("zoo3.in", "r", stdin);
    	n = read (); m = read (); c = read (); k = read ();
    	for (int i = 1; i <= n; i++) {
    		a = read (); s |= a;
    	}
    	for (int i = 1; i <= m; i++) {
    		p = read (); q = read ();
    		v[p]++;
    	}
    	int ans = 0;
    	for (int i = 0; i < k; i++) {
    		if (s >> i&1 || !v[i]) ans++;
    	}
    	if (ans == 0) {
    		printf ("0
    ");
    		return 0;
    	}
    	if (ans == 64 && n == 0) {
    		cout<<"18446744073709551616
    ";
    		return 0;
    	}
    	int Ans = (1ull << (ans - 1));
    	cout << Ans - n + Ans << endl; // 就像这样
    	return 0;
    }
    

    C(拓扑排序,建图)

    题目给出三个操作,单点加,全部乘,和调用几个函数。

    我们把所有的操作都看成一个个节点,根据调用关系建出一张图,因为保证不存在有递归,所以调用关系一定是一个DAG。

    做出贡献的点一定是出度为0的点,其他的点只是反复调用它们

    当我们使用乘这个操作时,会把前面的所有操作都乘上一个数,我们就可以逆着拓扑求一遍每个节点产生“乘”这个操作的贡献是多少

    同理,我们可以处理加法,由于处理乘法是为了得到后面的状态才去逆着推,但是加法需要得到当前的值,所以我们需要顺推

    此时,我们把乘法标记下放,然后先乘再加,即可得到当前的值

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N = 3e6, MOD = 998244353;
    struct Node {
        int next, to;
    } edge[N];
    int head[N], in[N], cnt;
    int ans[N], P[N], V[N], I[N], T[N], C[N];
    int n, m, q;
    int Q[N], r;
    inline int read () {
        int tot = 0, f = 1; char c = getchar ();
        while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar (); }
        while (c >= '0' && c <= '9') { tot = tot * 10 + c - '0'; c = getchar (); }
        return tot * f;
    }
    inline void add (int x, int y) {
        edge[++cnt].next = head[x];
        edge[cnt].to = y;
        head[x] = cnt;
        in[y]++;
    }
    inline int calc (int u) {
        if (T[u] != -1) return T[u]; T[u] = 1;
        for (int i = head[u]; i; i = edge[i].next)
            T[u] = T[u] * calc (edge[i].to) % MOD;
        return T[u];
    }
    signed main () {
        n = read ();
        for (int i = 1; i <= n; i++) add (0, i), P[i] = i, V[i] = read (), I[i] = 1, T[i] = 1;
        m = read ();
        for (int i = n + 1; i <= n + m; i++) {
            I[i] = read ();
            if (I[i] == 1) P[i] = read (), V[i] = read (), T[i] = 1;
            else if (I[i] == 2) T[i] = V[i] = read ();
            else { int k = read ();
                for (int j = 1; j <= k; j++) add (i, read() + n), T[i] = -1;
            }
        }
        for (int i = 1; i <= n + m; i++) calc (i);
        q = read ();
        for (int i = 1; i <= q; i++) add (0, read () + n);
        for (int i = 0; i <= n + m; i++) if (!in[i]) Q[++r] = i;
        I[0] = 3, C[0] = 1;
        while (r) {
            int u = Q[r], x = C[u]; r--;
            if (I[u] == 3) {
                for (int i = head[u]; i; i = edge[i].next) {
                    int v = edge[i].to;
                    C[v] = (x + C[v]) % MOD; in[v]--;
                    if (in[v] == 0) Q[++r] = v; x = x * T[v] % MOD;
                }
            }
            else if (I[u] == 1) ans[P[u]] = (1 * V[u] * x + ans[P[u]]) % MOD;
        }
        for (int i = 1; i <= n; i++) printf ("%d ", ans[i]);
        return 0;
    }
    

    感觉这个好看点

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int N=1e5+9,mod=998244353;
    vector<int> G[N],g[N];
    int n,m,q,mul[N],op[N],add[N],f[N];
    int Q[N],hh,tt,a[N],pos[N],in[N];
    int Add[N],Mul[N];
    inline int read()
    {
    	int res=0,f=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9') 
    	{
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    		res=(res<<3)+(res<<1)+ch-'0',ch=getchar();
    	return res*f;
    }
    
    inline void rev_toposort()
    {
    	hh=0,tt=-1;
    	for(int i=1;i<=m;i++) if(!in[i]) Q[++tt]=i;
    	while(hh<=tt)
    	{
    		int u=Q[hh++];
    		for(int i=0;i<g[u].size();i++)
    		{
    			int v=g[u][i];
    			mul[v]=1ll*mul[u]*mul[v]%mod;
    			if(--in[v]==0) Q[++tt]=v;
    		}
    	}
    }
    
    inline void toposort()
    {
    	memset(in,0,sizeof in);
    	for(int i=1;i<=m;i++)
    		for(int j=0;j<G[i].size();j++)
    			in[G[i][j]]++;
    	hh=0,tt=-1;
    	for(int i=1;i<=m;i++) if(!in[i]) Q[++tt]=i;
    	while(hh<=tt)
    	{
    		int u=Q[hh++];
    		for(int i=G[u].size()-1;i>=0;i--)
    		{
    			int v=G[u][i];
    			Add[v]=(Add[v]+Add[u])%mod;
    			Add[u]=1ll*Add[u]*mul[v]%mod;
    			if(--in[v]==0) Q[++tt]=v;	
    		}
    	}
    }
    
    int main()
    {
    	// freopen("call.in","r",stdin);
    	// freopen("call.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	m=read();
    	for(int i=1;i<N;i++) mul[i]=1;
    	for(int i=1;i<=m;i++)
    	{
    		op[i]=read();
    		if(op[i]==1) pos[i]=read(),add[i]=read();
    		if(op[i]==2) mul[i]=read();
    		if(op[i]==3)
    		{
    			int cnt;cnt=read();
    			while(cnt--)
    			{
    				int x;x=read();
    				g[x].push_back(i);in[i]++;
    				G[i].push_back(x);
    			}
    		}
    	}
    	rev_toposort();
    	q=read();
    	for(int i=1;i<=q;i++) f[i]=read();Mul[q+1]=1;
    	for(int i=q;i>=1;i--)
    	{
    		Mul[i]=1ll*Mul[i+1]*mul[f[i]]%mod;
    		Add[f[i]]=(Add[f[i]]+Mul[i+1])%mod;
    	}
    	for(int i=1;i<=n;i++) a[i]=1ll*a[i]*Mul[1]%mod;
    	toposort();
    	for(int i=1;i<=m;i++)
    		if(op[i]==1) a[pos[i]]=(a[pos[i]]+1ll*add[i]*Add[i]%mod)%mod;//printf("%d %d
    ",pos[i],Add[i]);
    	for(int i=1;i<=n;i++)
    		printf("%d ",a[i]);
    	return 0;
    }
    

    D

    我们来转换一下提意,题目就是给出一些蛇,从大到小进行决策“该不该吃最小的蛇”,并且每一条蛇都必须保证自己不会被吃掉。

    首先,我们可以得出一个结论:凡是做出过选择的蛇都会活到最后。

    那么我们就先假装所有的蛇都很蠢,只要自己不会最短就吃,但是即使成为了最短的蛇,也不一定会被吃,因为当时最长的蛇为了顾全大局会不敢冒险吃你,所以就存在一种奇偶性,因为后蛇不敢冒险,所以前蛇就敢吃,然后之后蛇又不敢冒险。

    用两个双端队列,一个存做出决策的蛇,一个存还没有做出决策的蛇

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 1e6 + 5;
    int T, n;
    deque <int> q1, q2;
    int a[N], val[N];
    inline int read () {
        int tot = 0, f = 1; char c = getchar ();
        while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar (); }
        while (c >= '0' && c <= '9') { tot = tot * 10 + c - '0'; c = getchar (); }
        return tot * f;
    }
    inline void init () {
        while (q1.size ()) q1.pop_back ();
        while (q2.size ()) q2.pop_back ();
        for (int i = 1; i <= n; i++) val[i] = a[i];
        q1.push_front(n);
        for (int i = 1; i < n; i++) q2.push_back (i);
    }
    inline int can (int x, int y) {
        if (x == y) return 0;
        if (val[x] < val[y]) return -1;
        if (val[x] > val[y]) return 1;
        if (x < y) return -1;
        if (x > y) return 1;
        return 0;
    }
    inline bool check () {
        if (q1.size () == 1) return 0;
        if (q1.size () == 2) return 1;
        int x = q1.front(); q1.pop_front();
        int y = q1.back(); q1.pop_back();
        val[y] -= val[x];
        if (can(y, q1.front()) < 0) {
            q1.push_front (y);
            return !check();
        }
        return 1;
    }
    inline bool calc () {
        if (q2.size () == 0) return 0;
        int siz = q1.size () + q2.size ();
        int x = q1.back(); q1.pop_back ();
        int y = q2.front(); q2.pop_front();
        val[x] -= val[y];
        while (q2.size () && can (x, q2.back ()) < 0) {
            q1.push_front (q2.back ());
            q2.pop_back ();
        } q1.push_front (x);
        if (q2.size ()) return 1;
        if (!check()) return 1;
        return 0;
    }
    inline int solve () {
        init ();
        int ans = n;
        while (calc ()) {
            ans --;
            // cout<<ans<<endl;
        }
        return ans;
    }
    signed main () {
        T = read () - 1; n = read ();
        for (int i = 1; i <= n; i++) a[i] = read ();
        printf ("%d
    ", solve());
        while (T--) {
            int k = read ();
            for (int i = 1; i <= k; i++) {
                int x = read (), y = read ();
                a[x] = y;
            }
            printf ("%d
    ", solve());
        }
        return 0;
    }
    
    

    E

    F

    G

    H

    I

    J(莫队,栈)

    大概意思就是说有一些数字,有一些询问,每次询问某个区间内只出现一次的数,如果有多个给出一个即可,支持离线

    直接用莫队,开个栈记录一下只出现一次的元素

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 5e5 + 5;
    struct Node {
        int l, r, id;
    } Ask[N];
    int block, a[N], belong[N];
    int n, q, sta[N], pos[N], ans[N], cnt[N];
    int top, l, r;
    inline int read () {
        int tot = 0, f = 1; char c = getchar ();
        while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar (); }
        while (c >= '0' && c <= '9') { tot = tot * 10 + c - '0'; c = getchar (); }
        return tot * f;
    }
    inline bool cmp (Node x, Node y) {
        if (belong[x.l] ^ belong[y.l]) return x.l < y.l;
        else if (belong[x.l] & 1) return x.r < y.r;
        else return x.r > y.r;
    }
    inline void add (int t) {
        cnt[t]++;
        if (cnt[t] == 1) {
            sta[++top] = t;
            pos[t] = top;
        }
        else if (cnt[t] == 2) {
            sta[pos[t]] = sta[top];
            pos[sta[top]] = pos[t];
            sta[top--] = pos[t] = 0;
        }
    }
    inline void del (int t) {
        cnt[t]--;
        if (cnt[t] == 1) {
            sta[++top] = t;
            pos[t] = top;
        }
        else if (cnt[t] == 0) {
            sta[pos[t]] = sta[top];
            pos[sta[top]] = pos[t];
            sta[top--] = pos[t] = 0;
        }
    }
    signed main () {
        n = read (); block = sqrt(n);
        for (int i = 1; i <= n; i++) a[i] = read (), belong[i] = i / block + 1;
        q = read ();
        for (int i = 1; i <= q; i++) {
            Ask[i].l = read (); Ask[i].r = read ();
            Ask[i].id = i;
        }
        sort (Ask + 1, Ask + 1 + q, cmp);
        /*for (int i = 1; i <= q; i++) {
            printf ("%d %d
    ", Ask[i].l, Ask[i].r);
        }*/
        l = r = 1;
        add (a[1]);
        for (int i = 1; i <= q; i++) {
            while (r < Ask[i].r) add (a[++r]);
            while (r > Ask[i].r) del (a[r--]);
            while (l < Ask[i].l) del (a[l++]);
            while (l > Ask[i].l) add (a[--l]);
            ans[Ask[i].id] = sta[top];
        }
        for (int i = 1; i <= q; i++)
            printf ("%d
    ", ans[i]);
        return 0;
    }
    

    K(模拟)

    显然......

    #include <bits/stdc++.h>
    using namespace std;
    int n, d;
    int ans, lax, x;
    inline int read () {
        int tot = 0, f = 1; char c = getchar ();
        while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar (); }
        while (c >= '0' && c <= '9') { tot = tot * 10 + c - '0'; c = getchar (); }
        return tot * f;
    }
    signed main () {
        n = read (); d = read (); lax = read ();
        for (int i = 2; i <= n; i++) {
            x = read (); if (x - lax == d * 2) ans++;
            else if (x - lax > d * 2) ans += 2;
            lax = x;
        }
        printf ("%d
    ", ans + 2);
        return 0;
    }
    

    L(模拟)

    显然01交错最优

    #include <bits/stdc++.h>
    using namespace std;
    int n, m;
    signed main () {
        cin >> n;
        for (int i = 1; i <= n; i++)
            cout<<i % 2;
        cout<<endl;
        return 0;
    }
    
    
  • 相关阅读:
    了解 Spring Data JPA
    Spring MVC 方法注解拦截器
    Spring MVC拦截器+注解方式实现防止表单重复提交
    java中return语句的用法总结
    equal方法在String类与Object类中的区别
    instanceof用法
    EL 简介及用法
    JAVA 四大域对象总结
    JSP基本语法
    Servlet请求转发 RequestDispatcher接口知识点
  • 原文地址:https://www.cnblogs.com/hulean/p/13960991.html
Copyright © 2020-2023  润新知