• HZNU Training 26 for Zhejiang Provincial Competition 2020


    POJ 3076 Sudoku
    思路:
    dfs + 剪枝
    首先,如果这个位置只能填一种字母,那就直接填
    其次,如果对于每一种字母,如果某一列或者某一行或者某一块只能填它,那就填它
    然后,对于某个位置如果不能填字母了,或者某种字母在一行一列或一块中出向了两次以上,说明当前方案不成立
    最后贪心地从可选情况少的往下搜

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<list>
    #include<map>
    #include<set>
    #include<sstream>
    #include<string>
    #include<vector>
    #include<cstdio>
    #include<ctime>
    #include<bitset>
    #include<algorithm>
    #include<string.h>
    #define L(x) (1 << (x))
    using namespace std;
    typedef long long ll;
    #define lson l , mid , rt << 1
    #define rson mid + 1 , read , rt << 1 | 1
    
    ll read()
    {
        ll 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 * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    
    const int maxn = 20;
    int mp[maxn][maxn];
    int st[maxn][maxn];
    int sum = 0;
    char s[maxn][maxn + 10];
    void add(int x, int y, int t) {
        mp[x][y] = t;
        sum++;
        for (int i = 1; i <= 16; i++) {
            st[i][y] |= 1 << t - 1;
            st[x][i] |= 1 << t - 1;
        }
        int xx = (x + 3) / 4, yy = (y + 3) / 4;
        for (int i = (xx - 1) * 4 + 1; i <= xx * 4; i++) {
            for (int j = (yy - 1) * 4 + 1; j <= yy * 4; j++) {
                st[i][j] |= 1 << t - 1;
            }
        }
    }
    void print() {
        for (int i = 1; i <= 16; i++) {
            for (int j = 1; j <= 16; j++) {
                putchar(mp[i][j] - 1 + 'A');
            }
            puts("");
        }
        puts("");
    }
    bool dfs() {
        if (sum == 256) {
            print();
            return true;
        }
    
        for (int i = 1; i <= 16; i++) {
            for (int j = 1; j <= 16; j++) {
                if (!mp[i][j]) {
                    int cnt = 0, t = 0;
                    for (int k = 1; k <= 16; k++) {
                        if ((st[i][j] & (1 << k - 1)) == 0) {
                            cnt++;
                            t = k;
                            if (cnt == 2) break;
                        }
                    }
                    if (!cnt) return false;
                    if (cnt == 1) add(i, j, t);
                }
            }
        }
    
        for (int i = 1; i <= 16; i++) {
            for (int k = 1; k <= 16; k++) {
                int cnt1 = 0, cnt2 = 0, y;
                for (int j = 1; j <= 16; j++) {
                    if (mp[i][j] == k) cnt1++;
                    if (cnt1 == 2) return false;
                    if (!mp[i][j] && (st[i][j] & (1 << k - 1)) == 0) cnt2++, y = j;
                }
                if (!cnt1 && !cnt2) return false;
                if (!cnt1 && cnt2 == 1) add(i, y, k);
            }
        }
    
        for (int j = 1; j <= 16; j++) {
            for (int k = 1; k <= 16; k++) {
                int cnt1 = 0, cnt2 = 0, x;
                for (int i = 1; i <= 16; i++) {
                    if (mp[i][j] == k) cnt1++;
                    if (cnt1 == 2) return false;
                    if (!mp[i][j] && (st[i][j] & (1 << k - 1)) == 0) cnt2++, x = i;
                }
                if (!cnt1 && !cnt2) return false;
                if (!cnt1 && cnt2 == 1) add(x, j, k);
            }
        }
    
        for (int i = 1; i <= 16; i++) {
            int x = (i + 3) / 4, y = i - (x - 1) * 4;
            for (int k = 1; k <= 16; k++) {
                int cnt1 = 0, cnt2 = 0, xx, yy;
                for (int ii = (x - 1) * 4 + 1; ii <= x * 4; ii++) {
                    for (int jj = (y - 1) * 4 + 1; jj <= y * 4; jj++) {
                        if (mp[ii][jj] == k) cnt1++;
                        if (cnt1 == 2) return false;
                        if (!mp[ii][jj] && (st[ii][jj] & (1 << k - 1)) == 0) cnt2++, xx = ii, yy = jj;
                    }
                }
                if (!cnt1 && !cnt2) return false;
                if (!cnt1 && cnt2 == 1) add(xx, yy, k);
            }
        }
        if (sum == 256) {
            print();
            return true;
        }
    
        int mn = maxn, x, y;
        for (int i = 1; i <= 16; i++) {
            for (int j = 1; j <= 16; j++) {
                if (!mp[i][j]) {
                    int cnt = 0;
                    for (int k = 1; k <= 16; k++) {
                        if ((st[i][j] & (1 << k - 1)) == 0) {
                            cnt++;
                            if (cnt >= mn) break;
                        }
                    }
                    if (cnt < mn) {
                        mn = cnt;
                        x = i;
                        y = j;
                    }
                }
            }
        }
        int tst[maxn][maxn], tmp[maxn][maxn];
        memcpy(tst, st, sizeof(st));
        memcpy(tmp, mp, sizeof(mp));
        int tsum = sum;
    
        for (int k = 1; k <= 16; k++) {
            if ((st[x][y] & (1 << k - 1)) == 0) {
                add(x, y, k);
                bool f = dfs();
                if (!f) {
                    memcpy(st, tst, sizeof(tst));
                    memcpy(mp, tmp, sizeof(tmp));
                    sum = tsum;
                }
                else return true;
            }
        }
        return false;
    }
    int main() {
        while (scanf("%s", s[1] + 1) != EOF) {
            for (int i = 2; i <= 16; i++) {
                scanf("%s", s[i] + 1);
            }
            sum = 0;
            memset(mp, 0, sizeof mp);
            memset(st, 0, sizeof st);
            for (int i = 1; i <= 16; i++) {
                for (int j = 1; j <= 16; j++) {
                    if (isalpha(s[i][j])) add(i, j, s[i][j] - 'A' + 1);
                }
            }
            dfs();
        }
        return 0;
    }
    View Code

    POJ 1741 Tree
    题目大意
    多组测试数据,每次输入n、m,和一棵n个点的有边权的树,问你满足x到y距离小于等于m的无序点对(x,y)的个数是多少。
    题解
    树的点分治模板题
    考虑到路径只有两种情况,一是经过根节点,二是不经过根节点。
    如果不经过根节点,那么一定经过最小公共子树的根节点,可以转化为问题一的子问题。
    于是考虑怎么递归解决问题一。
    对于根节点进行一次dfs,求出deep,并将其从小到大排序。
    避免重复,只需要求出其中deep[x]≤deep[y]且deep[x]+deep[y]≤m的个数。
    用i表示左指针,j表示右指针,i从左向右遍历。
    如果deep[i]+deep[j]≤m,则点对(i,t)(i<t≤j)都符合题意,将j-i加入答案中,并且i++;否则j--。
    然而这样还会重复计算在同一棵子树中的点对,所以再进行下一步dfs之前需要减去重复部分。
    因为树可能会退化,导致选择链头时时间复杂度极大而TLE。
    于是每次不能固定选择root,而是以重心作为root去处理,这样能保证时间复杂度再O(nlog2n)以下。

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<list>
    #include<map>
    #include<set>
    #include<sstream>
    #include<string>
    #include<vector>
    #include<cstdio>
    #include<ctime>
    #include<bitset>
    #include<algorithm>
    #include<string.h>
    #define L(x) (1 << (x))
    using namespace std;
    typedef long long ll;
    #define lson l , mid , rt << 1
    #define rson mid + 1 , read , rt << 1 | 1
    
    ll read()
    {
        ll 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 * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    
    const int maxn = 10010;
    int m;
    int head[maxn], to[maxn << 1], len[maxn << 1], net[maxn << 1];
    int cnt, si[maxn], deep[maxn], root, vis[maxn], f[maxn], sn, d[maxn];
    int tot, ans;
    void add(int x, int y, int z)
    {
        to[++cnt] = y, len[cnt] = z, net[cnt] = head[x], head[x] = cnt;
    }
    void getroot(int x, int fa)
    {
        f[x] = 0, si[x] = 1;
        int i;
        for (i = head[x]; i; i = net[i])
            if (to[i] != fa && !vis[to[i]])
                getroot(to[i], x), si[x] += si[to[i]], f[x] = max(f[x], si[to[i]]);
        f[x] = max(f[x], sn - si[x]);
        if (f[root] > f[x]) root = x;
    }
    void getdeep(int x, int fa)
    {
        d[++tot] = deep[x];
        int i;
        for (i = head[x]; i; i = net[i])
            if (to[i] != fa && !vis[to[i]])
                deep[to[i]] = deep[x] + len[i], getdeep(to[i], x);
    }
    int calc(int x)
    {
        tot = 0, getdeep(x, 0), sort(d + 1, d + tot + 1);
        int i = 1, j = tot, sum = 0;
        while (i < j)
        {
            if (d[i] + d[j] <= m) sum += j - i, i++;
            else j--;
        }
        return sum;
    }
    void dfs(int x)
    {
        deep[x] = 0, vis[x] = 1, ans += calc(x);
        int i;
        for (i = head[x]; i; i = net[i])
            if (!vis[to[i]])
                deep[to[i]] = len[i], ans -= calc(to[i]), sn = si[to[i]], root = 0, getroot(to[i], 0), dfs(root);
    }
    int main()
    {
        int n, i, x, y, z;
        while (scanf("%d%d", &n, &m) && (n || m))
        {
            memset(head, 0, sizeof(head));
            memset(vis, 0, sizeof(vis));
            cnt = 0, ans = 0;
            for (i = 1; i < n; i++)
                scanf("%d%d%d", &x, &y, &z), add(x, y, z), add(y, x, z);
            f[0] = 0x7fffffff, sn = n;
            root = 0, getroot(1, 0), dfs(root);
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code

    POJ 1852 Ants
    题目大意
    在一根长为L的水平木棍上有一群数量为n的蚂蚁,它们以每秒1cm/s的速度走到木棍一端就会掉下去。
    现在知道它们的起始位置是距离木根左端点的x处。但是不知道它们爬行的方向。
    在相向而行的两只蚂蚁相遇后,它们会掉头往反方向走。问所有蚂蚁都落下木棍的最快时间和最慢时间。
    题解
    因为是同时出发的,相遇时的两只蚂蚁用的时间是相同的,我们可以无视蚂蚁的区别,当两只蚂蚁相遇时它们保持原样交错而行。
    这样每只蚂蚁都是独立运动的,那么只要找每只蚂蚁掉下去的时间就行了。

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<list>
    #include<map>
    #include<set>
    #include<sstream>
    #include<string>
    #include<vector>
    #include<cstdio>
    #include<ctime>
    #include<bitset>
    #include<algorithm>
    #include<string.h>
    #define L(x) (1 << (x))
    using namespace std;
    typedef long long ll;
    #define lson l , mid , rt << 1
    #define rson mid + 1 , read , rt << 1 | 1
    
    ll read()
    {
        ll 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 * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    
    const int maxn = 1000010;
    int a[maxn];
    int ansmin, ansmax, L, n;
    int main()
    {
        int t;
        scanf("%d", &t);
        while (t--)
        {
            scanf("%d%d", &L, &n);
            for (int i = 0; i < n; ++i) {
                scanf("%d", &a[i]);
            }
    
            int minn;
            ansmin = -1;
            for (int i = 0; i < n; ++i)
            {
                minn = min(a[i], L - a[i]);
                if (minn > ansmin)
                    ansmin = minn;
            }
            printf("%d ", ansmin);
    
            int maxx;
            ansmax = -1;
            for (int i = 0; i < n; ++i)
            {
                maxx = max(a[i], L - a[i]);
                if (maxx > ansmax)
                    ansmax = maxx;
            }
            printf("%d
    ", ansmax);
        }
        return 0;
    }
    View Code

    POJ 2407 Relatives
    裸的欧拉函数,直接用公式

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<list>
    #include<map>
    #include<set>
    #include<sstream>
    #include<string>
    #include<vector>
    #include<cstdio>
    #include<ctime>
    #include<bitset>
    #include<algorithm>
    #include<string.h>
    #define L(x) (1 << (x))
    using namespace std;
    typedef long long ll;
    #define lson l , mid , rt << 1
    #define rson mid + 1 , read , rt << 1 | 1
    
    ll read()
    {
        ll 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 * 10 + ch - '0'; ch = getchar(); }
        return x * f;
    }
    
    int Q(int n)
    {
        int ans = n;
        for (int i = 2; i <= n; i++){
            if (n%i == 0){
                ans -= ans / i;
                while (n%i == 0) {
                    n /= i;
                }
            }
            if (n == 1) break;
        }
        return ans;
    }
    
    int main()
    {
        int n;
        while (cin >> n && n){
            cout << Q(n) << endl;
        }
        return 0;
    }
    View Code
  • 相关阅读:
    UILabel标签文字过长时的显示方式
    iOS8新特性之交互式通知
    iOS 音频学习
    UISegmentedControl小常识和图片拉伸
    iOS 锁屏判断
    UIwindow的学习
    Mac显示和隐藏系统的隐藏文件
    获取iOS系统版本和设备的电量
    React Native 学习-01
    如何用fir.im 命令行工具 打包上传
  • 原文地址:https://www.cnblogs.com/fengzhongzhuifeng/p/12797315.html
Copyright © 2020-2023  润新知