您的位置:首页 > 其它

湖南多校对抗赛(2015.05.10)(国防科大学校赛决赛-Semilive)CSU1609-1618

2016-05-11 23:03 627 查看
9/10

简单地写个题解,毕竟总个结很重要。但是由于题目水 + 不会写题解,路过的大牛莫喷。。。

题A

题意:给你两个序列a和b,有一种操作,对于一个数(非头尾)v,左边加上v,右边加上v,自己变成-v,然后问a操作无数次可不可以变成b?

题解:这题我学会了一个分析题目的方法:从目标逆着推。对于两个一样的序列,如下

操作前:……(i - 1) (i) (i + 1) ……

操作后:……(i - 1) + (i) (i) - (i) - (i) (i + 1) + (i)……

定义si为前i项的和,假设原序列为si - 1, si, si + 1,那么变化之后对应序列为si, si - 1,si + 1,所以这个操作的实质就是将前缀和变一下位置,所以对于两个序列我们只要求出前缀和s,然后sort一下看对应区域是否相等即可。

/*zhen hao*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <stack>
#include <string>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;

#define lson l, m, rt*2
#define rson m + 1, r, rt*2+1
#define xx first
#define yy second

typedef pair<int,int> pii;
typedef long long ll;

const int maxn = 1e4 + 10, mod = 1e9 + 7;
int fa[maxn], a[maxn], p[maxn];

void init_set(int n) {
for (int i = 0; i < n; i++) fa[i] = i;
}

int find_set(int rt) {
if (rt == fa[rt]) return rt;
return fa[rt] = find_set(fa[rt]);
}

void union_set(int u, int v) {
int fu = find_set(u), fv = find_set(v);
if (fu == fv) return;
fa[fu] = fv;
}

int main() {
//  freopen("case.in", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i <= m; i++) scanf("%d", a + i);
init_set(n);
for (int i = 0; i < n; i++) {
int ret = 0, base = 1;
for (int j = 0; j <= m; j++) {
ret = (ret + 1ll * base * a[j]) % n;
base = 1ll * base * i % n;
}
p[i] = ret;
}
for (int i = 0; i < n; i++) {
union_set(i, p[i]);
}
int ans = 1;
for (int i = 0; i < n; i++) {
if (i == find_set(i)) ans = ans * 2 % mod;
}
printf("%d\n", ans);
}
return 0;
}


代码君

最后一题,并不会,哈哈~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: