2020 CCPC Wannafly Winter Camp Day7 (Div.1&2)

pta
牛客

A. 序列

题意:
已知\(1\)\(n\)的一个排列。
现在给定一个数\(k\),对于这个排列的一个长度大于等于\(2\)的子序列\(s=(s_1,...,s_p),p≥2\), 对于每一个下标\(i\),如果满足:

  • \(i<p\)\(s_i<k<s_{i+1}\);
  • ​​\(i<p\)\(s_i>k>s_{i+1}\),那么得分加\(1\)

例如,当\(k=2\)时,子序列5134的得分就是2。
现在询问当\(k\)取遍\(1\)\(n\)时,所有给定排列的子序列的得分和是多少。

思路:

  • 我们可以单独考虑排列中每两个数\((i,j)\)对答案的贡献,显然两个数对答案的贡献为\(2^{n+p_i-p_j-1},p_i<p_j\)
  • 考虑枚举答案,当枚举到\(k\)时,我们需要考虑区间\([1,k-1],[k+1,n]\)中互相配对产生的贡献。
  • 假设已经处理完了答案为\(k\)的情况,现在要处理答案为\(k+1\)的情况,那么此时我们要处理的区间为\([1,k],[k+2,n]\)。观察区间的变化:发现我们需要加上\(k, [k+2,n]\)的贡献,减去\([1,k-1],k+1\)的贡献。
  • 那么我们从前往后、从后往前扫一遍预处理出贡献即可。预处理用树状数组实现单点修改、区间询问。

还有很多其它做法,个人感觉另外一种做法十分简单,用四个树状数组来直接统计答案:假设枚举到\(i\),那么两个树状数组记录\([i+1,n]\)的信息,两个树状数组记录\([1,i-1]\)的信息即可。
总时间复杂度\(O(nlogn)\)

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/21 16:11:43
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5, MOD = 1e9 + 7, inv2 = (MOD + 1) / 2;

struct Bit {
    int c[N];
    void init() {
        memset(c, 0, sizeof(c));
    }   
    int lowbit(int x) {return x & (-x);}
    void add(int x, int v) {
        for(; x < N; x += lowbit(x)) {
            c[x] = (c[x] + v) % MOD;
        }
    }
    int query(int x) {
        int res = 0;
        for(; x; x -= lowbit(x)) {
            res = (res + c[x]) % MOD;
        }
        return res;   
    }
    int query(int l, int r) {
        if(l > r) return 0;
        return (query(r) - query(l - 1) + MOD) % MOD;
    }
}bit, bit2;

int n, ans[N];
int a[N], b[N];
int l[N], r[N];
int f[N << 1], g[N << 1];

void run(){
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i], b[a[i]] = i;
    for(int i = 1; i <= n; i++) {
        bit.add(b[i], f[n + b[i] - 1]);
        bit2.add(b[i], (n - b[i] - 1 < 0 ? inv2 : f[n - b[i] - 1]));
        if(i + 2 <= n) {
            int t = bit.query(1, b[i + 2] - 1), t2 = bit2.query(b[i + 2] + 1, n);
            l[i + 2] = (1ll * t * g[b[i + 2]] % MOD + 1ll * t2 * f[b[i + 2]] % MOD) % MOD;
        }
    }
    bit.init(); bit2.init();
    for(int i = n; i >= 1; i--) {
        bit.add(b[i], f[n + b[i] - 1]);
        bit2.add(b[i], (n - b[i] - 1 < 0 ? inv2 : f[n - b[i] - 1]));
        if(i - 2 >= 1) {
            int t = bit.query(1, b[i - 2] - 1), t2 = bit2.query(b[i - 2] + 1, n);
            r[i - 2] = (1ll * t * g[b[i - 2]] % MOD + 1ll * t2 * f[b[i - 2]] % MOD) % MOD;
        }   
    }
    for(int i = 2; i < n; i++) {
        ans[i] = ((ans[i - 1] - l[i] + MOD) % MOD + r[i - 1]) % MOD;
    }
    for(int i = 1; i <= n; i++) {
        cout << ans[i] << '\n';
    }
}

void init() {
    f[0] = g[0] = 1;
    for(int i = 1; i < N << 1; i++) {
        f[i] = 1ll * f[i - 1] * 2 % MOD;
        g[i] = 1ll * g[i - 1] * inv2 % MOD;
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    init();
    run();
    return 0;
}

C. 10^5万

题意:
现有\(1...n\)的每种数字的牌各\(4\)张。玩家选择\(3k+1\)张牌,然后随机获得数字为\(1...n\)的一张牌(即使已经有\(4\)张有可能再次获得)。
现在给出\(n,L\),要求选出长度为\(3k+1\)的序列(\(k\)自己来定),使得这\(3k+2\)个数能够不重不漏地划分为一个对子和\(k\)个面子。对子即\("x\ x"\),面子即\("x\ x\ x","x\ x+1\ x+2"\)

思路:
构造题,其实可以通过样例猜出来。
我们直接按照模\(3\)的余数分类:

  • 对于模\(3\)\(1\)\(2\)的情况,我们直接\(1\ 1\ 1\ 2\ 2\ 2\cdots l-1\ \ l-1\ \ l-1\ \ l-1\)即可;
  • 对于模\(3\)\(0\)的情况,我们直接\(2\ 2\ 2\ \cdots l\ l\ l\ l\)即可。

至于正确性的证明,数据较小的情况我们可以直接验证,数据大的情况我们可以将其规约为数据较小的情况。规约方法为:最后四个拿出三个做面子,然后依次往前做面子即可,发现是以\(3\)为循环的,根据小情况就可以统计出方案数了。
代码如下:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/20 10:03:05
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;

int n, l;

void run(){
    cin >> n >> l;
    if(l == 2) {
        cout << 1 << '\n' << 1 << ' ' << 1 << ' ' << 2 << ' ' << 2 << '\n';
        return;
    }
    vector <int> ans;
    ans.push_back(1);   
    ans.push_back(1);   
    ans.push_back(1);   
    if(l % 3) {}
    else {
        if(n == l) {
            for(int i = 2; i < l; i++) ans.push_back(i);
            ans.push_back(l);
            ans.push_back(l);
            ans.push_back(l);
            cout << sz(ans) / 3 << '\n';
            for(int i = 0; i < sz(ans); i++) cout << ans[i] << " \n"[i == sz(ans) - 1];           
            return;
        } else {
            ans.clear(); ++l;
        }   
    }
    int now = 1;
    while(now + 1 < l) {
        ++now;
        ans.push_back(now);   
        ans.push_back(now);   
        ans.push_back(now);   
    }
    ans.push_back(now);
    cout << sz(ans) / 3 << '\n';
    for(int i = 0; i < sz(ans); i++) cout << ans[i] << " \n"[i == sz(ans) - 1];
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

F. 草莓

题意:
给出一个\(n\cdot m,n,m\leq 10^9\)的格子,从第一天开始,每天早上,每个格子会多出一个草莓。
一开始起点为\((x,y)\),每天下午可以选在待在原地或者向周围一个格子走去。
每天晚上会自动收割当前格子内的草莓。
现在问总共有\(k\)天,最多能收获多少草莓。

思路:
有几个比较重要的观察:

  • 考虑最后的局面,最优局面一定为格子中的权值由小到大为:\(0,1,\cdots,n\cdot m-1\)。因为产生草莓的总数量一样多,这样所剩的草莓最少。
  • 达到最优局面意味着:最后会将每个格子走一遍。
  • 格子中的草莓可以留着等最后一次经过时再采,这样可以方便计算。

\(n\cdot m\)为偶数,则必然存在一条哈密顿回路,所以我们直接等到最后再来走即可;
\(n\cdot m\)为奇数,此时我们能够遍历所有的格子的条件为起点\((x,y)\)满足\(x+y\)为偶数。

  • 证明方法分\(x,y\)奇偶性讨论,事实上我们只需要讨论\(x,y\)都为奇数的情况,这种情况最终一定会归约到一个\(n'\cdot m',n',m'\)为奇数的矩形且起点位于四个顶点之一的情况。因此可以直接走完。
  • 如果\(x+y\)为奇数,则其中一奇一偶。最终会规约到一个\(n'\cdot m',n',m'\)为奇数且起点为\((x',y'),x',y'\)一奇一偶的情况,显然不可能为四个顶点之一,最终不能走完。

回到这个题,如果一开始在的位置\(x+y\)为奇数,我们直接在第一天下午走一步即可。

以上讨论适用于\(n\geq 2,m\geq 2\)的情况,接下来考虑其中有一个为\(1\)的情况。
不妨\(n=1\),根据最初的观察,我们要使得\(0,1,\cdots\)这样的权值序列最长,那么就有以下的贪心方法:

  • \(k\)足够大,我们一开始走到一个角落里,然后等到最后\(m\)步将方格全部遍历一遍即可;
  • \(k\)比较小,我们就走\(k\)步即可;
  • \(k\)不大不小,我们选择往小的那一边走几步然后回头往另外一边走,并且保证要走到另一边的端点处。

最后\(n=1\)的情况实现起来要考虑一点细节,尤其是第三种情况,我们先把较长的那一段距离\(l\)求出来,然后\(\lfloor\frac{k-l}{2}\rfloor\)即是我们需要等待的时间,从第\(\lfloor\frac{k-l}{2}\rfloor+1\)天起走向另一边即可。
可能有点细节,还要注意取模,详见代码:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/20 15:42:30
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5, MOD = 998244353, inv2 = 499122177;

ll f(ll l, ll r) {
    if(l > r) return 0;
    return 1ll * (l + r) % MOD * ((r - l + 1) % MOD) % MOD * inv2 % MOD;  
}

void run(){
    ll n, m, x, y, k;
    cin >> n >> m >> x >> y >> k;
    if(m == 1) swap(n, m), swap(x, y);
    ll ans = 0, t = n * m;
    if(m == 1) {
        ans = k % MOD;
    } else if(n == 1) {
        ll d = max(min(y - 1, m - y) - 1, 0ll);
        if(k >= d + m) ans = f(k - m + 1, k);
        else if(k >= m - d) {
            ll l = m - d - 1;
            ans = f((k - l) / 2 + 1, k);
        } else ans = f(1, k);
    } else {
        if(k <= t) ans = f(1, k);
        else ans = f(k - t + 1, k);
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T;
    while(T--) run();
    return 0;
}

G. 草莓2

这个题就简单多了,\(n\cdot m\leq 12\)且保证至少有一个偶数,也就是怎么都存在哈密顿回路。
所以当\(k>n\cdot m\)的时候直接走哈密顿回路,\(k\leq n\cdot m\)时直接爆搜即可。

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/2/20 11:46:33
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 20 + 5;

int n, m, x, y;
ll k, ans;
int a[N][N];
pii T[N];

const int dx[] = {1, -1, 0, 0, 0}, dy[] = {0, 0, 1, -1, 0};

void dfs(int cur, int x, int y, int sum) {
    if(cur == k + 1) {
        ans = max(ans, (ll)sum);
        return;
    }
    int t = 0;
    for(int i = cur - 1; i > 0; i--) {
        if(T[i] == MP(x, y)) {
            t = i; break;
        }   
    }
    T[cur] = MP(x, y); 
    if(t == 0) sum += a[x][y] + cur - 1;
    else sum += cur - t;
    for(int i = 0; i < 5; i++) {
        int nx = x + dx[i], ny = y + dy[i];
        if(nx >= 1 && nx <= n && ny >= 1 && ny <= m) {
            dfs(cur + 1, nx, ny, sum);
        }   
    }
}

void run() {
    cin >> n >> m >> x >> y >> k;
    int sum = 0;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            cin >> a[i][j];
            sum += a[i][j];
        }
    }
    if(k > n * m) {
        int t = n * m;
        ans = sum + (t - 1) * t / 2;
        ans += 1ll * ((k - t) / t) * (t * t);
        ans += t * (k % t);
    } else {
        dfs(1, x, y, 0);
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

H. 游戏

考虑将所有删除的数字拿出来,最终总共会有\(n!\)总排列。
考虑每个质数对的贡献:

\[\frac{2\cdot \lfloor\frac{n}{2}\rfloor\cdot (n-2)!}{n!} \]

\(n\)为偶数,每一对的贡献为\(\frac{1}{n-1}\)
\(n\)为奇数,每一对的贡献为\(\frac{1}{n}\)
所以直接统计互质对数就行。

Code
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 5e3+5,MAXM = 1e6+5,MOD = 998244353,INF = 0x3f3f3f3f,N=2e5;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-7;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pii pair<int,int>
#define vii vector<pii>
#define vi vector<int>
#define x first
#define y second
using namespace std;

int n,primes[MAXN],phi[MAXN],cnt,sum[MAXN];
void init(){
    phi[1] = 1;
    for(int i=2;i<=5000;i++){
        if(!phi[i]){
            primes[cnt++] = i;
            phi[i] = i-1;
        }
        for(int j=0;j<cnt&&primes[j]*i<=5000;j++){
            if(i%primes[j]==0){
                phi[i*primes[j]] = phi[i]*primes[j];
                break;
            }
            phi[i*primes[j]] = phi[i] * (primes[j]-1);
        }
    }
    for(int i=2;i<=5000;i++)sum[i] = sum[i-1] + phi[i];
}
int gcd(int a,int b){
    return !b?a:gcd(b,a%b);
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    init();
    cin>>n;
    if(n==2){
        cout<<1<<'/'<<1<<'\n';
        return 0;
    }else if(n==1){
        cout<<0<<'/'<<1<<'\n';
        return 0;
    }
    int a = sum[n];
    int b = (n&1?n:n-1);
    int g = gcd(a,b);
    cout<<a/g<< '/'<<b/g<<'\n';
    return 0;
}

I. 圆

不太会。放上队友写的代码。

Code
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=(a); i<(b); i++)
using namespace std;
#define double long double
typedef long long ll;
#define MAXN 100007
double a[MAXN];
const double PI=acos(-1);
int main() {
	int n; scanf("%d", &n);
	REP(i,0,n) {
		scanf("%Lf", &a[i]);
		a[i]*=n;
	}
	sort(a,a+n);
	REP(i,0,n) {
		a[i] = 360.0*i-a[i];
	}
	sort(a,a+n);
//	int md=n/2;
		//double kk=a[md]/360;
		//int ku = (int)(ceil(kk)+0.1), kd=(int)(floor(kk)+0.1);
		double ans1=0;
		int l=0,r=n;
		while(l<r) {
			ans1+=fabs(a[r-1]-a[l]);
			l++,r--;
		}
/*	if((n&1) == 0) {
		double ans3=0, ans4=0;
		double kk=a[md-1]/360;
		int ku=(int)(ceil(kk)+0.1), kd=(int)(floor(kk)+0.1);
		REP(i,0,n) {
			ans3+=fabs(a[i]-ku*360.0);
			ans4+=fabs(a[i]-kd*360.0);
		}
		ans1=min(ans1,min(ans3,ans4));
	}*/
	printf("%.10Lf\n", ans1/n/180*PI);
	return 0;
}

K. 修炼

二分最短天数,然后贪心计算贡献即可。

Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
	int a1, a2; scanf("%d%d", &a1, &a2);
	//a1++, a2++;
	int n; scanf("%d", &n);
	int ans=(-1u)>>1;
	for(int i=0; i<n; i++) {
		int b1, b2; scanf("%d%d", &b1, &b2);
		ll l=0, r=max(b1,b2)*2;
		while(l<r) {
			ll m=(l+r)>>1;
			ll v1=m*a1, v2=m*a2;
			for(long long j=m; j>0; j--) {
				if(b1-v1>b2-v2) v1+=j;
				else v2+=j;
				if(v1>=b1 && v2>=b2) {r=m;goto nxt;}
			}
			l=m+1;
nxt:;
		}
		if(r<ans) ans=r;
	}
	printf("%d\n", ans);
	return 0;
}

L. 图

因为点数只有\(20\)个,所以总共的状态数只有\(2^{20}\)个,因此我们可以直接暴力计算所有状态,并且找到循环节。
我们把每个状态看作一个点,每个状态向另一个状态转化就相当于在状态图中连了一条有向边,那么最终图的形式一定为长度为\(l,l\geq 0\)的链+一个环。
求出这个之后,对于每组询问,我们只需要知道\(x\)点是否在环中、最终走到哪个位置就行。
可能会有一些细节,详见代码:

Code
/*
 * Author:  heyuhhh
 * Created Time:  2020/1/18 16:25:39
 */
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
//#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 20 + 1;

int n, m, q;
int a[N], d[N];

int cnt[N][1 << N], tot[N], num[N], sum[N];

vector <int> rg[N];
int mark[1 << N];

int get() {
    int res = 0;
    for(int i = 1; i <= n; i++) if(a[i]) {
        res ^= (1 << (i - 1));
    }   
    return res;
}

void run() {
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
        if(a[i]) cnt[i][++tot[i]] = 0;
    }
    for(int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        rg[v].push_back(u);
        d[v] ^= a[u];
    }
    memset(mark, -1, sizeof(mark));
    mark[get()] = 0;
    int len = 1 << n, s = 0;
    for(int T = 1; T < (1 << n); T++) {
        for(int u = 1; u <= n; u++) {
            if(d[u]) a[u] = 1;
            else a[u] = 0;
        }
        int tmp = get();
        if(mark[tmp] != -1) {
            s = mark[tmp];
            len = T - s;
            break;
        }
        mark[tmp] = T;
        for(int u = 1; u <= n; u++) {
            d[u] = 0;
            for(auto v : rg[u]) {
                d[u] ^= a[v];
            }
        }
        for(int i = 1; i <= n; i++) if(a[i]) {
            cnt[i][++tot[i]] = T;   
        }
    }
    for(int i = 1; i <= n; i++) {
        for(int T = 1; T <= tot[i]; T++) {
            if(cnt[i][T] >= s) break;
            ++sum[i];
        }
    }
    //cout << "--------" << '\n';
    //for(int i = 1; i <= n; i++) cout << sum[i] << ' ' << tot[i] << '\n';
    while(q--) {
        int x; ll k; cin >> x >> k;
        if(k <= (ll)sum[x]) {
            cout << cnt[x][k] << '\n';
            continue;   
        }
        if(tot[x] == sum[x]) {
            cout << -1 << '\n';
            continue;   
        }
        k -= sum[x];
        dbg(k);
        ll ans = s + 1ll * len * ((k - 1) / (tot[x] - sum[x]));
        dbg(ans);
        int r = k - 1ll * (tot[x] - sum[x]) * ((k - 1) / (tot[x] - sum[x]));
        dbg(r, sum[x]);
        ans += cnt[x][r + sum[x]] - s;
        cout << ans << '\n';
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    while(cin >> n >> m >> q) run();
    return 0;
}
posted @ 2020-02-20 20:45  heyuhhh  阅读(368)  评论(0编辑  收藏  举报