1. 程式人生 > >XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship

XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship

字串 line 同時 是否 數據 while bin mas 差分

A. Apple

按題意模擬即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 105, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, m;
vector<int>a[N];

int ind1 = 0, ind1num = 0;
int ind2num = 0;
int ind3 = 0, ind3num = 0;
bool vis[N];
int ind[N];

int cnt;
bool dfs1(int x, int fa)
{
    ++cnt;
    vis[x] = 1;
    for(auto y : a[x])if(y != fa)
    {
        if(!vis[y])
        {
            if(!dfs1(y, x))return 0;
        }
        else if(y != ind3)return 0;
    }
    return 1;
}

void dfs3(int x, int fa)
{
    ++cnt;
    vis[x] = 1;
    for(auto y : a[x])if(y != fa)
    {
        if(!vis[y])
        {
            dfs3(y, x);
        }
    }
}

bool solve()
{
    if(ind1num != 1)return 0;
    if(ind2num != n - 2)return 0;
    if(ind3num != 1)return 0;

    cnt = 0;
    vis[ind3] = true;
    if(!dfs1(ind1, 0))return 0;
    dfs3(ind3, 0);
    if(cnt != n)return 0;

    return 1;
}
int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
	while(~scanf("%d%d", &n, &m))
	{
        for(int i = 1; i <= n; ++i)
        {
            a[i].clear();
            ind[i] = 0;
            vis[i] = 0;
        }
        for(int i = 1; i <= m; ++i)
        {
            int x, y; scanf("%d%d", &x, &y);
            a[x].push_back(y);
            a[y].push_back(x);
            ++ind[x];
            ++ind[y];
        }
        ind1 = 0, ind1num = 0;
        ind2num = 0;
        ind3 = 0, ind3num = 0;
        for(int i = 1; i <= n; ++i)
        {
            if(ind[i] == 1)
            {
                ++ind1num;
                ind1 = i;
            }
            else if(ind[i] == 2)
            {
                ++ind2num;
            }
            else if(ind[i] == 3)
            {
                ++ind3num;
                ind3 = i;
            }
        }
        puts(solve() ? "Yes" : "No");
	}

	return 0;
}
/*
【trick&&吐槽】


【題意】


【分析】


【時間復雜度&&優化】
9 9
1 2
2 3
3 5
5 6
6 4
4 7
1 7
7 9
8 9

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

4 4
1 2
2 3
1 3
1 4

5 4
1 2
2 3
1 3
1 4


*/

  

B. Bar charts

關於序列的前綴和建立差分約束系統,SPFA判斷是否存在負環。

#include<cstdio>
#include<cstdlib>
using namespace std;
const int N=12222,M=1000000,E=10000000,inf=~0U>>1;
int n,i,g[N],v[M],w[M],nxt[M],ed,d[N];
int x,h,t,q[E];
int vis[N],in[N];
inline void add(int x,int y,int z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
inline void make(int x,int y,int z){
    //x-y=z
    add(y,x,z);
    add(x,y,-z);
}
void gao(){
    int k,b,s;
    scanf("%d%d%d",&k,&b,&s);
    make(b-1,0,0);
    for(int i=b+k*s;i<=n;i++)make(i,i-1,0);
    for(int i=1;i<=k;i++){
        int l=b+(i-1)*s,r=b+i*s;
        int o;
        scanf("%d",&o);
        //s[r-1]-s[l-1]
        make(r-1,l-1,o);
    }
}
void NO(){
    puts("No");
    exit(0);
}
inline void ext(int x,int y){
    if(y<0)NO();
    if(y>=d[x])return;
    d[x]=y;
    if(!in[x]){
        in[x]=1;
        vis[x]++;
        if(vis[x]>=n)NO();
        q[++t]=x;
        if(t>=E-10)NO();
    }
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    n=11111;
    for(i=0;i<n;i++)add(i+1,i,0);
    gao();
    gao();
    for(i=0;i<=n;i++){
        d[i]=inf;
    }
    h=1,t=0;
    ext(0,0);
    while(h<=t){
        x=q[h++];
        for(i=g[x];i;i=nxt[i])ext(v[i],d[x]+w[i]);
        in[x]=0;
    }
    puts("Yes");
}

  

C. Construction sets

二分答案,二進制拆分背包+bitset檢驗。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 55, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n, mn, mx;
int m[N], c[N];
bitset<10005>f;
bool check(int K)
{
    f.reset(); f[0] = 1;
    for(int i = 1; i <= n; ++i)
    {
        int tot = c[i] / K;
        int g = 1;
        LL v = m[i];
        while(tot)
        {
            if(v > mx)break;
            f |= f << v;
            tot -= g;
            g = min(g * 2, tot);
            v = (LL)m[i] * g;
        }
    }
    for(int j = mn; j <= mx; ++j)
    {
        if(f[j])return 1;
    }
    return 0;
}
int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
	while(~scanf("%d%d%d", &n, &mn, &mx))
	{
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d%d", &m[i], &c[i]);
        }
        int l = 0;
        int r = 1e6;
        while(l < r)
        {
            int mid = (l + r + 1) >> 1;
            if(check(mid))
            {
                l = mid;
            }
            else
            {
                r = mid - 1;
            }
        }
        printf("%d\n", l);
	}

	return 0;
}
/*
【trick&&吐槽】


【題意】


【分析】


【時間復雜度&&優化】
3 12 13
3 8
4 6
7 9

*/

  

D. Dinner party

$f[i][j]$表示面積和為$i$的矩形,周長和為$j$是否有可能,bitset加速。

#include<cstdio>
#include<bitset>
using namespace std;
const int N=1010,M=2010;
int T,n,m,i,j,x,y,cnt;
bitset<M>f[N];
void solve(){
    scanf("%d%d",&n,&m);
    if(m%2){
        puts("No");
        return;
    }
    m/=2;
    if(f[n][m]==0){
        puts("No");
        return;
    }
    puts("Yes");
    int cnt=0;
    static int q[100000][2];
    while(n){
        int X=0,Y=0;
        for(x=1;x<=n;x++){
            for(y=1;y*x<=n;y++)if(x+y<=m)if(f[n-x*y][m-x-y]){
                X=x,Y=y;
                break;
            }
            if(X)break;
        }
        q[++cnt][0]=X;
        q[cnt][1]=Y;
        n-=X*Y;
        m-=X+Y;
    }
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++)printf("%d %d\n",q[i][0],q[i][1]);
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    //scanf("%d%d",&n,&m);
    n=1000;
    m=2000;
    f[0][0]=1;
    for(i=0;i<=n;i++)
        for(x=1;x+i<=n;x++)
            for(y=1;x*y+i<=n;y++)
                f[i+x*y]|=f[i]<<(x+y);
    scanf("%d",&T);
    while(T--)solve();
}

  

E. Expression on dice

若要構造$=$,則在兩側構造$0$即可,否則隨意構造。

//
//  main.cpp
//  opencup 10378 E
//
//  Created by luras on 2017/9/14.
//  Copyright © 2017年 luras. All rights reserved.
//

#define ms(x, y) memset(x, y, sizeof(x))
#define mc(x, y) memcpy(x, y, sizeof(x))
#define lson o << 1, l, mid
#define rson o << 1 | 1, mid + 1, r
#define ls o << 1
#define rs o << 1 | 1
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<map>
#include<stack>
#include<time.h>
#include<vector>
#include<list>
#include<set>
#include<iostream>
#include<stdlib.h>
#include<string>
#include<algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")
template <class T> inline void gmax(T &a, T b){if(b > a) a = b;}
template <class T> inline void gmin(T &a, T b){if(b < a) a = b;}
using namespace std;
const int N = 1e6 + 10, M = 2e6 + 10, Z = 1e9 + 7, maxint = 2147483647, ms1 = 16843009, ms31 = 522133279, ms63 = 1061109567, ms127 = 2139062143;
const double PI = acos(-1.0), eps = 1e-8;
typedef long long LL;
void fre()
{
    freopen("/Users/luras/Desktop/in.txt", "r", stdin);
    freopen("/Users/luras/Desktop/out.txt", "w", stdout);
}
const int INF = 1e9;
int casenum, casei;

int priv[N];
double calc(double a, double b, char op)
{
    if(op == ‘+‘) return a + b;
    if(op == ‘-‘) return a - b;
    if(op == ‘*‘) return a * b;
    if(op == ‘/‘) return a / b;
    return 0;
}


double calculate(string str)
{
    stack<double> num;
    stack<char> oper;
    priv[‘+‘] = priv[‘-‘] = 3;
    priv[‘*‘] = priv[‘/‘] = 2;
    priv[‘(‘] = 10;
    double x, y, t = 0;
    int i; char last = 0;
    for(i = 0; i < str.length(); i ++){
        if(isdigit(str[i])){
            num.push(atof(str.c_str() + i));
            for(; i + 1 < str.length() && isdigit(str[i + 1]); i ++);
            if(i + 1 < str.length() && str[i + 1] == ‘.‘)
                for(i ++; i + 1 < str.length() && isdigit(str[i + 1]); i ++);
        }
        else if(str[i] == ‘(‘){
            oper.push(str[i]);
        }
        else if(str[i] == ‘)‘){
            while(oper.top() != ‘(‘){
                y = num.top(); num.pop();
                x = num.top(); num.pop();
                char op = oper.top();
                oper.pop();
                num.push(calc(x, y, op));
            }
            oper.pop();
        }
        else if(str[i] == ‘-‘ && (last == 0 || last == ‘(‘)){
            num.push(0.0);
            oper.push(‘-‘);
        }
        else if(priv[str[i]] > 0){
            while(oper.size() > 0 && priv[str[i]] >= priv[oper.top()]){
                y = num.top(); num.pop();
                x = num.top(); num.pop();
                char op = oper.top();
                oper.pop();
                num.push(calc(x, y, op));
            }
            oper.push(str[i]);
        }else continue;
        last = str[i];
    }
    while(oper.size() > 0){
        y = num.top(); num.pop();
        x = num.top(); num.pop();
        char op = oper.top();
        oper.pop();
        num.push(calc(x, y, op));
    }
    return num.top();
}

map<int, bool> mop;
vector<int> num;
vector<char> sym;
int lft, rgt, zero, divi, typ;


const string sta[6][6] ={
    {"=", "<", ">", "!=", "<=", ">="},
    {"4", "+", "-", "(", "(", ")"},
    {"0", "/", "/", "/", "8", "+"},
    {"2", "3", "4", "5", "-", ")"},
    {"+", "-", "*", "/", "1", "9"},
    {"6", "7", "+", "-", "(", ")"}
};


void ask(int o)
{
    char ch;
    if(o == 2){
        puts("2");
        fflush(stdout);
        scanf(" %c", &ch);
        //ch = sta[1][rand() % 6][0];
        //cout << "A: " << ch;
        if(ch == ‘(‘) lft ++;
        else if(ch == ‘)‘) rgt ++;
        else if(ch == ‘4‘) {
            num.push_back(ch);
            if(mop[ch] == 0){
                mop[ch] = 1;
                typ ++;
            }
        }
        else sym.push_back(ch);
    }
    else if(o == 3){
        puts("3");
        fflush(stdout);
        scanf(" %c", &ch);
        //ch = sta[2][rand() % 6][0];
        //cout << "A: " << ch;
        
        if(ch == ‘0‘) zero ++;
        else if(ch == ‘8‘) {
            num.push_back(ch);
            if(mop[ch] == 0){
                mop[ch] = 1;
                typ ++;
            }
        }
        else if(ch == ‘/‘) divi ++;
        else sym.push_back(ch);
    }
    else if(o == 4){
        puts("4");
        fflush(stdout);
        //ch = sta[3][rand() % 6][0];
        //cout << "A: " << ch;
        
        scanf(" %c", &ch);
        if(ch == ‘-‘) sym.push_back(ch);
        else if(ch == ‘)‘) rgt ++;
        else {
            num.push_back(ch);
            if(mop[ch] == 0){
                mop[ch] = 1;
                typ ++;
            }
        }
    }
}


string ans;
string s;
string ss;

int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    return x > 0 ? 1 : -1;
}

bool choose()
{
    s = "";
    int DIV = divi, ZERO = zero;
    int n = num.size(), m = sym.size() + DIV;
    int bas = (n + ZERO) / (m + 1);
    int mo = (n + ZERO) - (m + 1) * bas;
    int t = 0, j = -1, k = -1;
    for(int i = 0; i < m + 1; i ++){
        if(mo){
            if(j + 1 >= n) return 0; // 必須得放前導0了
            s += num[++ j]; ++ t;
            while(t <= bas && ZERO){
                s += ‘0‘; t ++; ZERO --;
            }
            while(t <= bas){
                s += num[++ j]; t ++;
            }
            mo --;
            t = 0;
        }
        else{
            if(j + 1 >= n) return 0;
            s += num[++ j]; ++ t;
            while(t < bas && ZERO){
                s += ‘0‘; t ++; ZERO --;
            }
            while(t < bas){
                s += num[++ j]; t ++;
            }
            t = 0;
        }
        if(DIV){
            s += ‘/‘;
            DIV --;
        }
        else{
            if(k + 1 < sym.size())s += sym[++ k];
        }
    }
    return 1;
}

bool check(int o)
{
    if(o == 0){
        zero -= 2; lft --; rgt --; divi --;
        if(!choose()) {zero += 2; lft ++; rgt ++; divi ++; return 0;}
        if(calculate(s) != 0){
            ans = "";
            for(int i = 0; i < lft; i ++) ans += ‘(‘;
            ans += ‘0‘;
            for(int i = 0; i < rgt; i ++) ans += ‘)‘;
            ans += "=0/(" + s + ‘)‘;
        }
        else {zero += 2; lft ++; rgt ++; divi ++; return 0;}
    }
    else{
        zero --;
        if(!choose()) {zero ++;return 0;}
        double tmp = calculate(s);
        if(sgn(tmp) != 0){
            if(ss[0] == ‘<‘ && sgn(tmp) > 0 || ss[0] == ‘>‘ && sgn(tmp) < 0){
                ans = "";
                for(int i = 0; i < lft; i ++) ans += ‘(‘;
                ans += ‘0‘;
                for(int i = 0; i < lft; i ++) ans += ‘)‘;
                ans += ss + s;
            }
            else{
                ans = "";
                for(int i = 0; i < lft; i ++) ans += ‘(‘;
                ans += s;
                for(int i = 0; i < lft; i ++) ans += ‘)‘;
                ans += ss + ‘0‘;
            }
        }
        else if(ss == "!="){
            ans = "";
            for(int i = 0; i < lft; i ++) ans += ‘(‘;
            ans += ‘0‘;
            for(int i = 0; i < lft; i ++) ans += ‘)‘;
            ans += ss + s;
            
        }
        else {zero ++; return 0;}
    }
    return 1;
}

int main()
{
    srand(time(NULL));
    //fre();
    puts("1");
    fflush(stdout);
    cin >> ss;
    //ss = sta[0][rand() % 6];
    //cout << ss << endl;
    lft = rgt = zero = divi = typ = 0;
    int tim = 0;
    while(1){
        if(++ tim == 1000){
            int go = 1;
        }
        if(zero < (ss[0] == ‘=‘ ? 2 : 1) || divi == 0){
            ask(3);
        }
        else if(lft < rgt || lft == 0){
            ask(2);
        }
        else if(num.size() - 2 < sym.size() || rgt < lft){
            ask(4);
        }
        else {
            if(check(ss[0] == ‘=‘ ? 0 : 1)) break;
            ask(4);
        }
    }
    printf("0 ");
    cout << ans << endl;
    fflush(stdout);
    return 0;
}

/*
 
 
 題意:
 
 類型:
 
 分析:
 
 優化:
 
 trick:
 
 數據:
 
 Sample Input
 
 Sample Output
 
 >=
 + / / + 8 0 ) ( ) ( - - 5 5 5 - 4 4 4 - 5 3
 
 */

  

F. Flight trip

留坑。

G. Glasses with solutions

找出的子集需要滿足$b\sum m-a\sum t=0$,折半搜索即可。

#include<cstdio>
#include<map>
using namespace std;
typedef long long ll;
const int N=40;
int n,m,A,B,i,x,y,a[N];map<ll,ll>f;
ll ans;
void dfsl(int x,ll y){
    if(x==m){f[y]++;return;}
    dfsl(x+1,y+a[x]);
    dfsl(x+1,y);
}
void dfsr(int x,ll y){
    if(x==n){ans+=f[-y];return;}
    dfsr(x+1,y+a[x]);
    dfsr(x+1,y);
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d%d%d",&n,&A,&B);
    for(i=0;i<n;i++){
        scanf("%d%d",&x,&y);
        a[i]=x*B-A*y;
    }
    m=n/2;
    dfsl(0,0);
    dfsr(m,0);
    ans--;
    printf("%lld",ans);
}

  

H. Hamburgers

對於每個漢堡,$O(2^6)$枚舉所有它可以滿足的口味,然後對於每個人判斷是否滿足即可。

時間復雜度$O(m\sum a+2^6\sum b)$。

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=55555;
int n,m,i,j,k,x,ans[N],mx[N],b[N];
vector<int>a[N];
bool v[(1<<26)+5];
inline int get(){
    static char s[1000];
    scanf("%s",s);
    int t=0,len=strlen(s);
    for(int i=0;i<len;i++)t|=1<<(s[i]-‘a‘);
    return t;
}
inline void make(int x,int y){
    for(int i=x;i;i=(i-1)&x)v[i]=y;
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d",&k);
        while(k--){
            x=get();
            a[i].push_back(x);
        }
        ans[i]=1;
    }
    scanf("%d",&m);
    for(i=1;i<=m;i++){
        scanf("%d",&k);
        for(j=1;j<=k;j++)b[j]=get();
        for(j=1;j<=k;j++)make(b[j],1);
        for(j=1;j<=n;j++){
            int t=0;
            for(x=0;x<a[j].size();x++)if(v[a[j][x]])t++;
            if(t>mx[j])mx[j]=t,ans[j]=i;
        }
        for(j=1;j<=k;j++)make(b[j],0);
    }
    for(i=1;i<=n;i++)printf("%d\n",ans[i]);
}
/*
5
1
a
3
a
ba
cb
3
vba
d
ba
3
ca
da
da
3
as
ba
af
2
4
abc
abcd
a
a
2
abcdef
abcdev
*/

  

I. Intricate path

留坑。

J. Jumps through the Hyperspace

顯然到每個點的時間越早越好,對於每種傳送門預處理出每種余數下的最優等待時間即可。

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef pair<int,int>P;
const int N=2010,inf=~0U>>1;
int n,m,st,i,j,a[N],b[N],c[N],d[N],w[N][N];
int f[N];
char g[N][N],op[N];
priority_queue<P,vector<P>,greater<P> >q;
inline void ext(int x,int y){
    if(f[x]>y)q.push(P(f[x]=y,x));
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d%d%d",&n,&m,&st);
    while(m--){
        scanf("%s",op);
        int o=op[0];
        scanf("%d%d%d%d",&a[o],&b[o],&c[o],&d[o]);
        for(i=0;i<c[o];i++){
            w[o][i]=inf;
            for(j=0;j<c[o];j++)w[o][i]=min(w[o][i],(a[o]*(i+j)+b[o])%c[o]+d[o]+j);
        }
    }
    for(i=1;i<=n;i++)scanf("%s",g[i]+1);
    for(i=1;i<=n;i++)f[i]=inf;
    ext(1,st);
    while(!q.empty()){
        P t=q.top();q.pop();
        if(f[t.second]<t.first)continue;
        for(i=1;i<=n;i++)if(g[t.second][i]!=‘.‘)
            ext(i,t.first+w[g[t.second][i]][t.first%c[g[t.second][i]]]);
    }
    if(f[n]==inf)puts("-1");else 
    printf("%d",f[n]-st);
}

  

K. King’s island

暴力搜索出一個上凸殼,然後翻轉拼接起來得到完整的多邊形即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x, y) memset(x, y, sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; }
const int N = 1010, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f;
template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; }
int casenum, casei;
int n;
struct B
{
    int x, y;
    bool operator < (const B & b)const
    {
        //y/x > b.y/b.x
        return y * b.x > x * b.y;
    }
};
B p[100000]; int g;
int f[N][N][62];
struct A
{
    int x, y, z;
};
bool bingo[60];
vector<B>ans[60];

void getvt(int x, int y, int v, vector<B>&vt, int DX, int DY)
{
    if(v == 0)return;
    int o = f[x][y][v];
    if(f[x - p[o].x][y - p[o].y][v] == o)
    {
        getvt(x - p[o].x, y - p[o].y, v, vt, DX + p[o].x, DY + p[o].y);
    }
    else
    {
        vt.push_back({p[o].x + DX, p[o].y + DY});
        getvt(x - p[o].x, y - p[o].y, v - 1, vt, 0, 0);
    }
}

void init()
{
    for(int i = 1; i <= 200; ++i)
    {
        for(int j = i + 1; j <= 200; ++j)if(__gcd(i, j) == 1)
        {
            int W = (i * i + j * j);
            int w = sqrt(W);
            if(w * w == W)
            {
                p[++g] = {i, j};
                p[++g] = {j, i};
            }
        }
    }
    sort(p + 1, p + g + 1);
    //printf("%d\n", g);

    MS(f, 0);
    f[0][0][0] = 1;
    for(int i = 0; i <= 500; ++i)
    {
        for(int j = 0; j <= 500; ++j)
        {
            for(int v = 29; v >= 0; --v)if(f[i][j][v])
            {
                //
                int k = f[i][j][v];
                auto &it = f[i + p[k].x][j + p[k].y][v];
                if(it == 0)it = k;
                //
                for(int k = f[i][j][v] + 1; k <= g; ++k)
                {
                    auto &it = f[i + p[k].x][j + p[k].y][v + 1];
                    if(it == 0)it = k;
                }
                if(i == 0 || j == 0)continue;
                for(int u = 1; u + v <= 30; ++u)if(f[i][j][u] && f[i][j][u] != f[i][j][v])
                {
                    if(!bingo[u + v])
                    {
                        bingo[u + v] = 1;
                        vector<B>up, down;
                        getvt(i, j, u, up, 0, 0);
                        getvt(i, j, v, down, 0, 0);
                        int x = i;
                        int y = j;
                        //printf("%d %d %d\n", u + v, up.size(), down.size());
                        //puts("up------------");
                        for(int r = 0; r < up.size(); ++r)
                        {
                            x -= up[r].x;
                            y -= up[r].y;
                            ans[u + v].push_back({x, y});
                            //printf("%d %d\n", up[r].x, up[r].y);
                        }
                        //puts("down------------");
                        for(int r = 0; r < down.size(); ++r)
                        {
                            x += down[r].x;
                            y += down[r].y;
                            ans[u + v].push_back({x, y});
                            //printf("%d %d\n", down[r].x, down[r].y);
                        }
                        //puts("ans------");
                        for(auto w : ans[u + v])
                        {
                            //printf("%d %d\n", w.x, w.y);
                        }
                        int pasue = 1;
                    }
                }
            }
        }
    }
    for(int i = 1;i <= 30; ++i)
    {
        //printf("%d\n", bingo[i]);
    }
}
int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    init();
	while(~scanf("%d", &n))
	{
	    if(n == 3)
        {
            puts("0 0\n4 3\n-20 21");
            continue;
        }
        for(auto it : ans[n])
        {
            printf("%d %d\n", it.x, it.y);
        }
	}

	return 0;
}
/*
【trick&&吐槽】


【題意】


【分析】


【時間復雜度&&優化】
28 195
9 15
-116 178
4
20 21
1 -159
-236 -11
-92 6
5
20 50
3 -94
-16 -274
-236 18
-92 35


*/

  

L. Lexica

無視同一行/同一列的兩個格子的位置關系,只需要在它們不相同時將方案數乘$2$,如此一來只關心每一行/每一列有多少格子沒滿足。

設$f[i][j][S][k]$表示考慮到$(i,j)$,每一列剩余情況為$S$,第$i$行還有$k$個格子需要填充時的方案數,然後逐格轉移即可。

時間復雜度$O(n3^n)$。

#include<cstdio>
typedef unsigned long long ll;
const int N=18,M=1600000;
int n,m,all,i,j,k,x,y,z,A,B,C,S,o,p[N],mask,cnt[N];
char a[N][N];
int e;
ll f[2][M][3],mul;
int w[M];
inline void clr(){
    for(int i=0;i<=mask;i++)for(int j=0;j<3;j++)f[e^1][i][j]=0;
}
inline void nxt(){
    //for(int i=0;i<=mask;i++)for(int j=0;j<3;j++)f[i][j]=g[i][j];
}
inline int get(int S,int x){
    return S/p[x]%3;
}
void dfs(int x,int y,int z){
		if(x==n){
			w[y]=z;
			return;
		}
		for(int i=0;i<3;i++)dfs(x+1,y*3+i,z*2+(!!i));
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d",&n);
    m=n+2;
    for(i=0;i<m;i++)scanf("%s",a[i]);
    mul=1;
    for(p[0]=i=1;i<N;i++)p[i]=p[i-1]*3;
    all=p[n];
    for(i=1;i<=n;i++){
        if(a[0][i]!=‘#‘&&a[m-1][i]!=‘#‘&&a[0][i]!=a[m-1][i])mul*=2;
        if(a[i][0]!=‘#‘&&a[i][m-1]!=‘#‘&&a[i][0]!=a[i][m-1])mul*=2;
        if(a[i][0]!=‘#‘)cnt[i]++;
        if(a[i][m-1]!=‘#‘)cnt[i]++;
        if(a[0][i]!=‘#‘)mask+=p[i-1];
        if(a[m-1][i]!=‘#‘)mask+=p[i-1];
    }
    dfs(0,0,0);
    f[0][mask][0]=mul;
    for(i=1;i<=n;i++){
        clr();
        int o=cnt[i];
        for(A=0;A<=mask;A++)f[e^1][A][o]=f[e][A][0];
        e^=1;
        for(j=0;j<n;j++)if(a[i][j+1]==‘.‘){
            clr();
            for(S=0;S<=mask;S++){
            		if(w[S]>>j&1)for(k=0;k<=o;k++)if(f[e][S][k])f[e^1][S-p[j]][k]+=f[e][S][k];
            		for(k=1;k<=o;k++)if(f[e][S][k])f[e^1][S][k-1]+=f[e][S][k];
            }
            e^=1;
        }
    }
    printf("%llu",f[e][0][0]);
}
/*
5
##ARRR#
H.#.##S
Y.....E
O.#.#.E
##....E
###.#.E
#XNT#A#
*/

  

M. Maximal paths

樹形DP求出每個點內部從葉子往上、從上往下的最大數字串即可。需要手寫高精度。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
typedef __int128 lll;
const int N=10000010,M=50;
const ll MO=1000000000000000000ULL;
int n,i;char a[N];
struct P{
    ll v[3];
    P(){v[0]=v[1]=v[2]=0;}
    P operator+(int b){
        P c;
        for(int i=0;i<3;i++)c.v[i]=v[i];
        c.v[0]+=b;
        for(int i=0;i<2;i++)if(c.v[i]>=MO){
            c.v[i+1]+=c.v[i]/MO;
            c.v[i]-=MO;
        }
        return c;
    }
    P operator+(const P&b){
        P c;
        for(int i=0;i<3;i++)c.v[i]=v[i]+b.v[i];
        for(int i=0;i<2;i++)if(c.v[i]>=MO){
            c.v[i+1]+=c.v[i]/MO;
            c.v[i]-=MO;
        }
        return c;
    }
    P operator*(int b){
        P c;
        for(int i=0;i<3;i++)c.v[i]=v[i]*b;
        for(int i=0;i<2;i++)c.v[i+1]+=c.v[i]/MO,c.v[i]%=MO;
        c.v[2]%=MO;
        return c;
    }
    P operator*(const P&b){
        P c;
        static lll f[3];
        f[0]=f[1]=f[2]=0;
        for(int i=0;i<3;i++)if(v[i])for(int j=0;i+j<3;j++)if(b.v[j])f[i+j]+=(lll)v[i]*b.v[j];
        for(int i=0;i<2;i++)if(f[i]>=MO)f[i+1]+=f[i]/MO,f[i]%=MO;
        if(f[2]>=MO)f[2]%=MO;
        for(int i=0;i<3;i++)c.v[i]=f[i];
        return c;
    }
    void up(const P&b){//max=
        int i;
        for(i=2;~i;i--)if(b.v[i]!=v[i])break;
        if(i<0)return;
        if(b.v[i]<v[i])return;
        for(i=0;i<3;i++)v[i]=b.v[i];
    }
    void write(){
        int i=2;
        while(i&&!v[i])i--;
        printf("%llu",v[i]);
        for(int j=i-1;~j;j--)printf("%018llu",v[j]);
        puts("");
    }
}f[M],g[M],p[M],ans,ff,gg,mx[M];
int d[M];
unsigned int seed,base;
void dfs(int x,int k){
    f[k]=g[k]=mx[k]=P();
    d[k]=0;
    for(int i=0;i<2;i++){
        int y=x<<1|i;
        if(y>n)continue;
        dfs(y,k+1);
        ff=(f[k+1]*10)+((int)a[y]);
        gg=g[k+1]+(p[d[k+1]]*((int)a[y]));
        mx[k].up((ff*p[d[k]])+g[k]);
        mx[k].up((f[k]*p[d[k+1]+1])+gg);
        /*if(x==1){
            puts("debug");
            ff.write();
            f[k].write();
        }*/
        f[k].up(ff);
        g[k].up(gg);
        d[k]=max(d[k],d[k+1]+1);
        /*if(x==1){
            puts("debug");
            ff.write();
            f[k].write();
        }*/
    }
   /* printf("%d:\n",x);
    f[k].write();
    g[k].write();
    mx[k].write();*/
    ans=ans+mx[k];
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d%u",&n,&seed);
    base=(1U<<31)-1;
    p[0].v[0]=1;
    for(i=1;i<M;i++)p[i]=p[i-1]*10;
    for(i=1;i<=n;i++){
        a[i]=((seed&base)>>16)%9+1;
        seed=seed*1103515245+12345;
        //printf("%d\n",a[i]); i and i/2
    }
    dfs(1,0);
    ans.write();
}

  

XVII Open Cup named after E.V. Pankratiev. XXI Ural Championship