分类目录归档:算法

Openjudge 打印月历

http://noi.openjudge.cn/ch0113/24/

描述
给定年月,打印当月的月历表。

输入
输入为一行两个整数,第一个整数是年份year(1900 ≤ year ≤ 2099),第二个整数是月份month(1 ≤ month ≤ 12),中间用单个空格隔开。

输出
输出为月历表。月历表第一行为星期表头,如下所示:
Sun Mon Tue Wed Thu Fri Sat
其余各行一次是当月各天的日期,从1日开始到31日(30日或28日)。
日期数字应于星期表头右对齐,即各位数与星期表头相应缩写的最后一个字母对齐。日期中间用空格分隔出空白。

样例输入

1
2006 5

样例输出

1
2
3
4
5
6
Sun Mon Tue Wed Thu Fri Sat
      1   2   3   4   5   6
  7   8   9  10  11  12  13
 14  15  16  17  18  19  20
 21  22  23  24  25  26  27
 28  29  30  31

提示
闰年判断方法:能被4整除但不能被100整除,或者能被400整除。
1900年1月1日是周一。
继续阅读

洛谷 P2742 [USACO5.1]圈奶牛Fencing the Cows /【模板】二维凸包

开心啦! THUOJ不过不知道是什么鬼畜精度问题,不管了^v^
板子好用^v^

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include<iostream>
#include<iomanip>
#include<string>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
struct point {
    double x, y;
    long long id;
    point() :x(0), y(0) {}
    bool operator ==(const point& p) const {
        return x == p.x && y == p.y;
    }
}PP; //PP: Polar Point
vector<point> points;
double area2(point p, point q, point s) {
    /*
    |p.x p.y 1|
    |q.x q.y 1| == 2*DirectedTriangleArea(p,q,s)
    |s.x s.y 1|
    */

    return p.x * q.y - s.x * q.y
        + q.x * s.y - q.x * p.y
        + s.x * p.y - p.x * s.y;
}
bool toLeftTest(point p, point q, point s) {
    //When return value large than 0, S is on the left side of ray PQ
    return area2(p, q, s) > 0;
}
bool toLeftTest2(point p, point q, point s) {
    //When return value large than 0, S is on the left side of ray PQ
    return area2(p, q, s) >= 0;
}
bool cmp(const point& p1, const point& p2) { // Sort according to polar angle
    return PP == p1 || !(PP == p2) && toLeftTest(PP, p1, p2);
}
point LTL(vector<point>& points) { //Lowest then leftmost
    point ltl = points[0];
    for (int i = 1; i < points.size(); i++) {
        if (points[i].y < ltl.y || points[i].y == ltl.y && points[i].x < ltl.x)
            ltl = points[i];
    }
    return ltl;
}
vector<point> grahamScan() {
    PP = LTL(points);
    sort(points.begin(), points.end(), cmp);
    vector<point> S, T;
    S.push_back(points[0]); S.push_back(points[1]);
    for (int i = points.size() - 1; i > 1; i--)T.push_back(points[i]);
    while (!T.empty()) {
        if (toLeftTest2(S[S.size() - 2], S[S.size() - 1], T[T.size() - 1])) {
            S.push_back(T[T.size() - 1]);
            T.pop_back();
        }
        else S.pop_back();
    }
    return S;
}
double dist(point x, point y) {
    return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y));
}
int main() {
    ios::sync_with_stdio(false);
    long long n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        point tmp;
        cin >> tmp.x >> tmp.y;
        tmp.id = i;
        points.push_back(tmp);
    }
    vector<point> result;
    if (points.size() > 2)result = grahamScan();
    else result = points;
    double res = 0;
    for (int i = 0; i < result.size(); i++) {
        res += dist(result[i % result.size()], result[(i + 1) % result.size()]);
    }
    cout.setf(ios::fixed);
    cout << setprecision(2) << res;
}

CG2017 PA1-1 Convex Hull (凸包)

开始接触计算几何啦!!!

CG2017 PA1-1 Convex Hull (凸包)


Description (描述)

After learning Chapter 1, you must have mastered the convex hull very well. Yes, convex hull is at the kernel of computational geometry and serves as a fundamental geometric structure. That’s why you are asked to implement such an algorithm as your first programming assignments.

Specifically, given a set of points in the plane, please construct the convex hull and output an encoded description of all the extreme points.

经过了第一章的学习,想必你对于凸包的认识已经非常深刻。是的,凸包是计算几何的核心问题,也是一种基础性的几何结构。因此你的第一项编程任务,就是来实现这样的一个算法。

具体地,对于平面上的任意一组点,请构造出对应的凸包,并在经过编码转换之后输出所有极点的信息。

Input (输入)

The first line is an integer n > 0, i.e., the total number of input points.

The k-th of the following n lines gives the k-th point:

pk = (xk, yk), k = 1, 2, …, n

Both xk and yk here are integers and they are delimited by a space.

第一行是一个正整数首行为一个正整数n > 0,即输入点的总数。

随后n行中的第k行给出第k个点:

pk = (xk, yk), k = 1, 2, …, n

这里,xk与yk均为整数,且二者之间以空格分隔。

Output (输出)

Let { s1, s2, …, sh } be the indices of all the extreme points, h ≤ n. Output the following integer as your solution:

( s1 * s2 * s3 * … * sh * h ) mod (n + 1)

若 { s1, s2, …, sh } 为所有极点的编号, h ≤ n,则作为你的解答,请输出以下整数:

( s1 * s2 * s3 * … * sh * h ) mod (n + 1)

Sample Input (输入样例)


10
7 9
-8 -1
-3 -1
1 4
-3 9
6 -4
7 5
6 6
-6 10
0 8

Sample Output (输出样例)


7   // ( 9 x 2 x 6 x 7 x 1 x 5 ) % (10 + 1)

Limitation (限制)

  • 3 ≤ n ≤ 10^5
  • Each coordinate of the points is an integer from (-10^5, 10^5). There are no duplicated points. Each point is selected uniformly randomly in (-10^5, 10^5) x (-10^5, 10^5).
  • All points on extreme edges are regarded as extreme points and hence should be included in your solution.
  • Time Limit: 2 sec
  • Space Limit: 512 MB
  • 3 ≤ n ≤ 10^5
  • 所有点的坐标均为范围(-10^5, 10^5)内的整数,且没有重合点。每个点在(-10^5, 10^5) x (-10^5, 10^5)范围内均匀随机选取
  • 极边上的所有点均被视作极点,故在输出时亦不得遗漏
  • 时间限制:2 sec
  • 空间限制:512 MB

Hint (提示)

Use the CH algorithms presented in the lectures.

课程中讲解过的凸包算法

 

分数:92.5
使用Graham Scan算法。凸包板子题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
struct point {
    long long x, y, id;
    point() :x(0), y(0) {}
    point(long long x, long long y) :x(x), y(y) {}
    bool operator ==(const point& p) const {
        return x == p.x && y == p.y;
    }
}PP; //PP: Polar Point
vector<point> points;
long long area2(point p, point q, point s) {
    /*
    |p.x p.y 1|
    |q.x q.y 1| == 2*DirectedTriangleArea(p,q,s)
    |s.x s.y 1|
    */

    return p.x * q.y - s.x * q.y
        + q.x * s.y - q.x * p.y
        + s.x * p.y - p.x * s.y;
}
bool toLeftTest(point p, point q, point s) {
    //When return value large than 0, S is on the left side of ray PQ
    return area2(p, q, s) > 0;
}
bool toLeftTest2(point p, point q, point s) {
    //When return value large than 0, S is on the left side of ray PQ
    return area2(p, q, s) >= 0;
}
bool cmp(const point& p1, const point& p2) { // Sort according to polar angle
    return PP == p1 || !(PP == p2) && toLeftTest(PP, p1, p2);
}
point LTL(vector<point>& points) { //Lowest then leftmost
    point ltl = points[0];
    for (int i = 1; i < points.size(); i++) {
        if (points[i].y < ltl.y || points[i].y == ltl.y && points[i].x < ltl.x)
            ltl = points[i];
    }
    return ltl;
}
vector<point> grahamScan() {
    PP = LTL(points);
    sort(points.begin(), points.end(), cmp);
    vector<point> S, T;
    S.push_back(points[0]); S.push_back(points[1]);
    for (int i = points.size() - 1; i > 1; i--)T.push_back(points[i]);
    while (!T.empty()) {
        if (toLeftTest2(S[S.size() - 2], S[S.size() - 1], T[T.size() - 1])) {
            S.push_back(T[T.size() - 1]);
            T.pop_back();
        }
        else S.pop_back();
    }
    return S;
}
int main() {
    ios::sync_with_stdio(false);
    long long n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        point tmp;
        cin >> tmp.x >> tmp.y;
        tmp.id = i;
        points.push_back(tmp);
    }
    vector<point> result;
    if (points.size() > 2)result = grahamScan();
    else result = points;
    long long res = 1;
    for (int i = 0; i < result.size(); i++) {
        //cout << result[i].id << endl;//debug
        res = ((res % (n + 1)) * (result[i].id % (n + 1))) % (n + 1);
    }
    res = ((res % (n + 1)) * (result.size() % (n + 1))) % (n + 1);
    cout << res;
}

BJD CTF Programming notakto_1

不知名CTF比赛的不知名题目,类井字棋,要写程序判断。
写了两个程序:如下:
C++有漏洞,够用就行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<iostream>
#include<algorithm>
using namespace std;
int process[10] = { 4 };
bool visited[10];
inline int cal(int x, int y) {
    return x * 3 + y;
}
bool& vis(int x, int y) {
    return visited[cal(x, y)];
}
bool check(int x, int y) {
    bool flag = false;
    flag |= vis(0, y) & vis(1, y) & vis(2, y);
    flag |= vis(x, 0) & vis(x, 1) & vis(x, 2);
    if (x == y)flag |= vis(0, 0) & vis(1, 1) & vis(2, 2);
    if (x + y == 2)flag |= vis(0, 2) & vis(1, 1) & vis(2, 0);
    return flag;
}
void print(int n) {
    for (int i = 0; i <= n; i++) {
        cout << process[i];
    }
    cout << endl;
}
void dfs(int step) {
    bool flag = true;
    for (int i = 0; i < 9; i++) {
        if (visited[i])continue;
        visited[i] = true;
        process[step] = i;
        if (check(i / 3, i % 3) == 0) {
            dfs(step + 1);
            flag = false;
        }
        visited[i] = false;
    }
    if (flag&&step%2==1)print(step);
}
int main() {
    visited[4] = true;
    dfs(1);
}

python连带着往外发socket麻烦得很:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from pwn import *
sock = remote("222.186.56.247",8122)
wordList = []
currentWord = ""

def findNewWord():
    global currentWord,wordList
    for elem in wordList:
        if elem[0:len(currentWord)]==currentWord:
            return elem
    raise Exception("Error:Word Not found!")

def loadDic():
    global wordList
    with open("situation.txt","r") as f:
        wordList = f.readlines()
   
def getIntfromSock(sock):
    sock.recvuntil("My move: ")
    x = sock.recv(1)
    if x==b' ': x = sock.recv(1)
    return int(x)

def payGame(i):
    global currentWord,wordList,sock
    print("the ith:",i)
    currentWord=""
    while len(currentWord) < 5:
        backupWord = findNewWord()
        print("Send:",backupWord[len(currentWord)])
        sock.sendline(str(backupWord[len(currentWord)]))
        currentWord += backupWord[len(currentWord)]
        if len(currentWord)==5:
            print("break")
            break
        currentWord += str(getIntfromSock(sock))
        print("currentWord",currentWord)
    sock.recvuntil("win!")

loadDic()
for i in range(150):
    payGame(i)
sock.interactive()

代码链接:notakto

lower_bound/upper_bound简易实现

lower_bound:

1
2
3
4
5
6
7
8
9
int lower_bound(int v) { //arr[1..n],arr[0..n-1]
    int l = 0, r = n-1,mid;
    while (l < r) {
        mid = (l + r) / 2;
        if (arr[mid]<v)l=mid+1;
        else r = mid;
    }
    return l;
}

upper_bound:

1
2
3
4
5
6
7
8
9
int upper_bound(int v) { //arr[1..n],arr[0..n-1]
    int l = 0, r = n-1,mid;
    while (l < r) {
        mid = (l + r) / 2;
        if (arr[mid]<=v)l=mid+1;
        else r = mid;
    }
    return l;
}

洛谷 P4777 【模板】扩展中国剩余定理(EXCRT)

照着教程想了一下午,终于A了。。。
参考文章:
https://www.luogu.org/blog/niiick/solution-p4777
https://www.luogu.org/problemnew/solution/P4777
https://blog.csdn.net/xiaobian_/article/details/87949337

扩展欧几里得算法与中国剩余定理


https://www.cnblogs.com/yangsongyi/p/9867057.html
(快速乘规避溢出)
https://www.cnblogs.com/jt2001/p/6129914.html
https://blog.csdn.net/qq_39599067/article/details/81118467

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
ll b[100005], a[100005]; //b是余数,a是模数
ll quickmultiply(ll a, ll b,ll mod) {
    if (b == 0)return 0;
    ll result = quickmultiply(a, b / 2, mod) % mod;
    result = 2*result%mod;
    if (b & 1)result = (result+a)%mod;
    return result;
}
ll ngcd(ll a, ll b) {
    return b == 0 ? a : ngcd(b, a % b);
}
ll exgcd(ll a, ll b, ll& x, ll& y) {
    if (b == 0) {
        x = 1; y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
ll excrt() {
    ll lcm = a[1], ans = b[1];
    for (int i = 2; i <= n; i++) {
        ll k1, k2, K, mod = lcm;
        ll gcd = exgcd(lcm, a[i], k1, k2);
        ll minus = ((b[i] - ans) % a[i] + a[i]) % a[i];
        if ((minus % ngcd(lcm, a[i]) != 0))return -1;
        K = (quickmultiply(k1,(minus / gcd),(a[i] / gcd)) + a[i] / gcd) % (a[i] / gcd);
        lcm *= a[i] / gcd, ans = (K * mod + ans) % lcm;
    }
    return (ans % lcm + lcm) % lcm;
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i] >> b[i];
    }
    cout<<excrt();
}

洛谷 P3381 【模板】最小费用最大流

参考链接:https://www.cnblogs.com/widerg/p/9394929.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int eN = 100005;
const int vN = 10005;
const int INF = 0x7f7f7f7f;
int n, m, s, t;
int ePtr = -1; //e的实际存储只能从偶数号顶点开始,奇数号顶点存储反向边
int to[eN << 1], nxt[eN << 1], value[eN << 1], cost[eN << 1];
int head[vN], dis[vN], minV[vN];
int preID[eN << 1], preNode[eN << 1];
bool inqueue[vN];
inline void createEdge(int u, int v, int w, int c) {
    to[++ePtr] = v;
    value[ePtr] = w;
    cost[ePtr] = c;
    nxt[ePtr] = head[u];
    head[u] = ePtr;
}
bool SPFA(int s, int t) {
    queue<int> q;
    memset(dis, 0x7f, sizeof(dis));
    memset(inqueue, false, sizeof(inqueue));
    memset(preID, -1, sizeof(preID));
    memset(preNode, -1, sizeof(preNode));
    memset(minV, 0x7f, sizeof(minV));
    dis[s] = 0;
    inqueue[s] = true;
    q.push(s);
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        inqueue[x] = false;
        for (int i = head[x]; ~i; i = nxt[i]) {
            int dest = to[i];
            if (dis[dest] > dis[x] + cost[i] && value[i]) {
                dis[dest] = dis[x] + cost[i];
                minV[dest] = min(minV[x], value[i]);
                preID[dest] = i;
                preNode[dest] = x;
                if (!inqueue[dest]) {
                    inqueue[dest] = true;
                    q.push(dest);
                }
            }
        }
    }
    return dis[t] != INF;
}
void MinCostMaxFlow(int s, int t, int& maxflow, int& mincost) {
    while (SPFA(s, t)) {
        for (int i = t; i != s; i = preNode[i]) {
            value[preID[i]] -= minV[t];
            value[preID[i] ^ 1] += minV[t];
        }
        maxflow += minV[t];
        mincost += minV[t] * dis[t];
    }
}
int main() {
    memset(head, -1, sizeof(head));
    scanf("%d%d%d%d", &n, &m, &s, &t);
    for (int i = 1; i <= m; i++) {
        int u, v, w, f;
        scanf("%d%d%d%d", &u, &v, &w, &f);
        createEdge(u, v, w, f);
        createEdge(v, u, 0, -f);//第0号边被占用,这条语句为反向边留下空间
    }
    int maxflow = 0, mincost = 0;
    MinCostMaxFlow(s, t, maxflow, mincost);
    printf("%d %d\n", maxflow, mincost);
}

洛谷 P3376 【模板】网络最大流

参考链接:https://www.cnblogs.com/widerg/p/9387909.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int eN = 100005;
const int vN = 10005;
const int INF = 0x7f7f7f7f;
int n, m, s, t;
int ePtr = -1; //e的实际存储只能从偶数号顶点开始,奇数号顶点存储反向边
int to[eN<<1], nxt[eN<<1], value[eN<<1];
int head[vN], dis[vN];
inline void createEdge(int u, int v, int w) {
    to[++ePtr] = v;
    value[ePtr] = w;
    nxt[ePtr] = head[u];
    head[u] = ePtr;
}
bool bfs(int s, int t) {
    queue<int> q;
    memset(dis, 0x7f, sizeof(dis));
    dis[s] = 0;
    q.push(s);
    while (!q.empty()) {
        int x = q.front();
        q.pop();
        for (int i = head[x]; ~i; i = nxt[i]) {
            int dest = to[i];
            if (dis[dest] == INF && value[i] != 0) {
                dis[dest] = dis[x] + 1;
                q.push(dest);
            }
        }
    }
    return dis[t] != INF;
}
int dfs(int x, int t, int maxflow) {
    if (x == t)return maxflow;
    int ans = 0;
    for (int i = head[x]; ~i; i = nxt[i]) {
        int dest = to[i];
        if (dis[dest] != dis[x] + 1 || value[i] == 0 || ans >= maxflow)continue;
        int f = dfs(dest, t, min(value[i], maxflow - ans));
        value[i] -= f;
        value[i ^ 1] += f;
        ans += f;
    }
    return ans;
}
int dinic(int s, int t) {
    int ans = 0;
    while (bfs(s, t))ans += dfs(s, t, INF);
    return ans;
}
int main() {
    memset(head, -1, sizeof(head));
    scanf("%d%d%d%d", &n, &m, &s, &t);
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        createEdge(u, v, w);
        createEdge(v, u, 0);//第0号边被占用,这条语句为下一个边留下空间
    }
    printf("%d", dinic(s, t));
}

Codeforces 102346 problem K Keep Calm and Sell Balloons

这道题重点要说矩阵快速幂,公式不会推。用了一个Berlekamp-Massey algorithm的模板。最主要想将一般情况下线性递推式怎么用矩阵快速幂优化。
本题目的递推公式是:F(n)=6*F(n-1)-8*F(n-2)-8*F(n-3)+16*F(n-4)
故构造矩阵递推公式:
\begin{bmatrix}
F(n) \\
F(n-1) \\
F(n-2) \\
F(n-3)
\end{bmatrix} =
\begin{bmatrix}
6 & -8 & -8 & 16 \\
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0
\end{bmatrix} *
\begin{bmatrix}
F(n-1) \\
F(n-2) \\
F(n-3) \\
F(n-4)
\end{bmatrix}


\begin{bmatrix}
F(n) \\
F(n-1) \\
F(n-2) \\
F(n-3)
\end{bmatrix} =
\begin{bmatrix}
6 & -8 & -8 & 16 \\
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0
\end{bmatrix}^{n-4} *
\begin{bmatrix}
F(4) \\
F(3) \\
F(2) \\
F(1)
\end{bmatrix}


对于一般的线性递推公式F(n)=a_1*F(n-1)+a_2*F(n-2)+…+a_{k-1}*F(n-k+1)+a_k*F(n-k)
可以构造一长宽都为k的矩阵,满足:
\begin{bmatrix}
F(n) \\
F(n-1) \\
… \\
F(n-k+2) \\
F(n-k+1)
\end{bmatrix} =
\begin{bmatrix}
a_1 & a_2 & … & a_{n-k+1} & a_{n-k} \\
1 & 0 & … & 0 & 0 \\
0 & 1 & … & 0 & 0 \\
… & … & … & … & … \\
0 & 0 & … & 1 & 0
\end{bmatrix} *
\begin{bmatrix}
F(n-1) \\
F(n-2) \\
… \\
F(n-k+1) \\
F(n-k)
\end{bmatrix}

因此只需对该矩阵做快速幂,即可以以O(k^3logn)的复杂度推出任意n情况下的数列的值。
本题代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
using namespace std;
const long long MOD = 1e9 + 7;
const int maxtrixN=4;
struct matrix {
    long long arr[maxtrixN][maxtrixN];
    matrix operator * (matrix m2) {
        matrix result;
        long long(&arr)[maxtrixN][maxtrixN] = result.arr;
        const long long(&arr1)[maxtrixN][maxtrixN] = this->arr;
        const long long(&arr2)[maxtrixN][maxtrixN] = m2.arr;
        for (int i = 0; i < maxtrixN; i++) {
            for (int j = 0; j < maxtrixN; j++) {
                arr[i][j] = 0;
                for (int k = 0; k < maxtrixN; k++) {
                    arr[i][j] += arr1[i][k] * arr2[k][j] % MOD;
                    arr[i][j] += MOD;
                    arr[i][j] %= MOD;
                }
            }
        }
        return result;
    }
};
const matrix c = { 6,-8,-8,16,1,0,0,0,0,1,0,0,0,0,1,0 };
matrix quickpow(long long n) {
    if (n == 1)return c;
    matrix half = quickpow(n / 2);
    matrix result = half * half;
    if (n & 1)result = result * c;
    return result;
}
long long getValue(long long n) {
    matrix result = quickpow(n);
    long long(&arr)[4][4] = result.arr;
    return (arr[0][0] * 1536 % MOD + arr[0][1] * 416 % MOD + arr[0][2] * 96 % MOD + arr[0][3] * 24 % MOD +MOD) % MOD;
}
int main() {
    int n;
    long long a1[] = { 0,2,24,96,416,1536 };
    cin >> n;
    if (n < 6)cout << a1[n];
    else cout << getValue(n-5);
}