WannaflyUnion每日一题
Posted 蒻
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WannaflyUnion每日一题相关的知识,希望对你有一定的参考价值。
---恢复内容开始---
1、
http://www.spoj.com/problems/KAOS/
题意:给定n个字符串,统计字符串(s1, s2)的对数,使得s1的字典序比s2的字典序要大,s1反一反(abc->cba,记为s1’)比s2’的字典序要小。
做法:先把字符串排序,当我们把s[i]当成题意中的s1的时候,j > i,s[j]是不用管的,那我们只需要用Trie树按序插入s\',然后统计答案。
#include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <time.h> #include <string> #include <stack> #include <set> #include <map> #include <iostream> #include <bitset> #include <algorithm> using namespace std; #define MP make_pair #define PB push_back typedef long long LL; typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f; const LL INF = (1uLL << 63) - 1; const LL mod = 1000000007; const int N = 150 + 5; const double Pi = acos(-1.0); const int maxn = 1e5 + 5; int trie[maxn << 4][27]; int cnt[maxn << 4]; int tol = 0; struct node{ char s[11]; bool operator < (const node & a)const{ return strcmp(a.s,s) > 0; } }S[maxn]; int sum(int x) { int len = strlen(S[x].s); int now = 0; int res = 0; for(int i = len - 1; i >= 0; i--) { int id = S[x].s[i] - \'a\'; for(int j = id + 1; j < 26; j++) { res += cnt[trie[now][j]]; } now = trie[now][id]; } for(int i = 0; i < 26; i++)res += cnt[trie[now][i]]; return res; } int is(int x) { int len = strlen(S[x].s); int now = 0; for(int i = len - 1; i >= 0; i--) { int id = S[x].s[i] - \'a\'; if(!trie[now][id]) { trie[now][id] = ++tol; } now = trie[now][id]; ++cnt[now]; } return sum(x); } int main() { #ifdef local freopen("in", "r", stdin); // freopen("w","w",stdout); #endif // ios::sync_with_stdio(false); // cin.tie(0); int n; LL ans = 0; scanf("%d",&n); for(int i = 0; i < n; i++)scanf("%s",S[i].s); sort(S,S+n); for(int i = 0; i < n; i++) { ans = ans + is(i); } printf("%lld\\n",ans); }
2、
http://www.spoj.com/problems/STARSBC/
题意:一个圆上有n个等分点,现在从一个点出发,指定k,不停地隔k个点连边(样例请看link),问有多少种不同的方法,使得所有的点都被连起来。两种情况是一样的,当且仅当他们旋转若干角度以后是一样的。
做法:要能把所有点连起来那么gcd(k,n)肯定等于1,因为要把所有点连起来也就表示 k * x % n 能得到0 - n - 1所有值,一开始x为0时,k * x % n = 0,如果找到一个y使得k * y % n = 0,那就会陷入一个循环了,如果gcd(k,n)等于c,那k * n / c % n是等于0的,也就是说当点移动了n / c次后它就会陷入循环,很明显c取1的时候才能走完所有点,那这题就是要求出gcd(x,n)==1,且x < n的所有x,但是要去掉重复的,什么时候两个情况会一样呢。假如两个k分别取x , y,当x + y等于n的时候这两种情况就会一样了,这个画图看一下就行了,证明略,gcd(x,n) == gcd(n - x, n)这个结论也好推,所以当gcd(x,n)等于1那gcd(n - x,n)也等于1,那答案就等于欧拉(n) / 2.
#include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <time.h> #include <string> #include <stack> #include <set> #include <map> #include <iostream> #include <bitset> #include <algorithm> using namespace std; #define MP make_pair #define PB push_back typedef long long LL; typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f; const LL INF = (1uLL << 63) - 1; const LL mod = 1000000007; const int N = 150 + 5; const double Pi = acos(-1.0); const int maxn = 1e5 + 5; int prime[maxn]; bool vis[maxn]; int tol; void init() { for(int i = 2; i < maxn; i++) { if(!vis[i])prime[tol++] = i; for(int j = 0; j < tol && i * prime[j] < maxn; j++){ vis[i * prime[j]] = 1; if(i % prime[j] == 0)break; } } } int main() { #ifdef local freopen("in", "r", stdin); // freopen("w","w",stdout); #endif //ios::sync_with_stdio(false); //cin.tie(0); init(); int n; while(~scanf("%d", &n)) { int ans = n; int cnt = 0; while(cnt < tol && prime[cnt] * prime[cnt] <= n) { if(n % prime[cnt] == 0) { ans -= ans / prime[cnt]; while(n % prime[cnt] == 0)n /= prime[cnt]; } cnt++; } if(n > 1) { ans -= ans / n; } ans >>= 1; printf("%d\\n", ans); } }
3、
http://www.spoj.com/problems/ODDDIV/
题意:给出一个正奇数K,两个正整数low,high。有多少整数属于[low, high],且包含K个因子。
做法:K是正奇数,表示n = p1 ^ m1 * p2 ^ m2 * ... * pk^mk,约数个数是(m1+1)*(m2+1)*...*(mk+1)那m肯定是偶数,所以我们可以bfs拓展一下,把k所有情况都跑出来,这样的数不会很多,数量在1e6左右,跑出来之后排序,二分结果就行了
//题解出了。自己弱智了点,因为m的数量是偶数,那这些数肯定是平方数,所以直接枚举2 - 1e5的平方来预处理就可以了,不用写这样麻烦的拓展
#include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <time.h> #include <string> #include <stack> #include <set> #include <map> #include <iostream> #include <bitset> #include <algorithm> using namespace std; #define MP make_pair #define PB push_back typedef long long LL; typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f; const LL INF = (1uLL << 63) - 1; const LL mod = 1000000007; const int N = 150 + 5; const double Pi = acos(-1.0); const int maxn = 1e5 + 5; int prime[maxn]; bool vis[maxn]; int tol; void init() { for(int i = 2; i < maxn; i++) { if(!vis[i])prime[tol++] = i; for(int j = 0; j < tol && i * prime[j] < maxn; j++) { vis[i * prime[j]] = 1; if(i % prime[j] == 0)break; } } } vector<LL>A[maxn]; struct node { int h; LL Num; int _k; }; queue<node>Q; void bfs() { node start = (node) { -1, 1, 1 }; A[1].PB(1); Q.push(start); while(!Q.empty()) { node now = Q.front(); Q.pop(); for(int i = now.h + 1; i < tol; i++) { LL p = prime[i]; LL F = p * p; LL die = 1; int num; for(num = 2; ; num += 2) { die *= F; if(die <= 10000000000LL / now.Num && now._k * (num + 1) <= 100000) { A[now._k * (num + 1)].PB(now.Num * die); Q.push((node) { i, now.Num * die, now._k * (num + 1) }); } else break; } if(num == 2)break; } } } bool vi[maxn]; int k; int bs(LL x) { int l = 0, r = A[k].size(); while(l + 1 < r) { int mid = (l + r) >> 1; if(A[k][mid] <= x) { l = mid; } else r = mid; } while(l >= 0 && A[k][l] > x) { l--; } return l; } int main() { #ifdef local freopen("in", "r", stdin); // freopen("w","w",stdout); #endif ios::sync_with_stdio(false); cin.tie(0); init(); bfs(); int T; cin >> T; while(T--) { LL l, r; cin >> k >> l >> r; if(!vi[k]) { sort(A[k].begin(), A[k].end()); vi[k] = 1; } cout<< upper_bound(A[k].begin(), A[k].end(), r) -upper_bound(A[k].begin(), A[k].end(), l - 1)<<endl;; } }
4、
http://codeforces.com/contest/287/problem/D
题意:
定义排列p = p1, p2, ..., pn。
定义函数f(p, k)用来转换p排列,k是转换参数, k > 1。
假设排列p的长度为n,首先把p按长度k进行分块,若最后一块长度不足k,则其长度为n%k,然后分别对每一块循环左移一位,得到一个新的排列。
给定n,请输出 f(f(...f(p = [1,2,...,n],2)...,n-1,),n)的结果。
n <= 1e6
做法:
把f(p,k)右移一位,发现这个序列就是原本序列p的一个子序列(下标modk==1的数组成的)右移一位得到,所以我们把p的那个子序列先右移,再把整个序列左移就相当于进行了一次操作,每次的复杂度是n/k + 1,n / 2 + n / 3 + ... n / n 这样的复杂度是nlogn.用数组模拟一下
#include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <time.h> #include <string> #include <stack> #include <set> #include <map> #include <iostream> #include <bitset> #include <algorithm> using namespace std; #define MP make_pair #define PB push_back typedef long long LL; typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f; const LL INF = (1uLL << 63) - 1; const LL mod = 1000000007; const int N = 150 + 5; const double Pi = acos(-1.0); const int maxn = 1e6 + 5; int Q[maxn << 1]; char ch[11]; int num; inline void out(int x){ num = 0; while(x)ch[++num] = x % 10, x /= 10; while(num)putchar(ch[num--] + 48); } int main() { #ifdef local freopen("in", "r", stdin); // freopen("w","w",stdout); #endif // ios::sync_with_stdio(false); // cin.tie(0); int n; cin>>n; for(int i = 1; i <= n; i++)Q[i] = i; for(int i = 2; i <= n; i++){ int x = 0; for(int j = i - 1; j < n + i - 1; j += i){ swap(x,Q[j]); } Q[n + i - 1] = x; } for(int i = n; i < n << 1; i++){ out(Q[i]); putchar(\' \'); } }
5、
http://codeforces.com/contest/21/problem/D
题意:
给出一个无向带权图,问从1号点出发,通过所有的边至少一次,再回到1号点,需要花费的最少代价是多少。存在自环和重边。
如果无法满足上述要求,那么输出-1。
节点数n,边数m。(1 <= n <= 15, 0 <= m <= 2000)
每条边包含3个属性u, v, w, u和v是边的端点,w是通过边的代价。(1 <= x,y <= n, 1 <= w <= 1e4)。
做法:
从一个点出发走完全部边然后回到原点,这个就是欧拉回路,欧拉回路的条件是全部度数都是偶数,如果有不为偶数度数的点,我们可以把这些点互相连起来,使得这些点都变成偶数点,这是一定可行的,因为奇数度数的点必定有偶数个,这个操作我们可以用dfs也可以用状压dp来搞。连起来的时候的边权就是这两点之间的最短距离,这个最短距离我们可以通过Floyd预处理来弄。
#include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <time.h> #include <string> #include <stack> #include <set> #include <map> #include <iostream> #include <bitset> #include <algorithm> using namespace std; #define MP make_pair #define PB push_back typedef long long LL; typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f; const LL INF = (1uLL << 63) - 1; const LL mod = 1000000007; const int N = 150 + 5; const double Pi = acos(-1.0); const int maxn = 1e6 + 5; int E[21][21]; int d[21]; int sum = 0; bool vis[21]; int cnt = 0; int num[21]; int dfs(int cur) { if(cur == cnt)return 0; if(vis[cur]) { return dfs(cur + 1); } vis[cur] = 1; int res = inf; for(int i = 0; i < cnt; i++) { if(!vis[i]) { vis[i] = 1; res = min(res , E[num[cur]][num[i]] + dfs(cur + 1)); vis[i] = 0; } } vis[cur] = 0; return res; } int dp[1<<16]; int main() { #ifdef local freopen("in", "r", stdin); // freopen("w","w",stdout); #endif ios::sync_with_stdio(false); cin.tie(0); memset(E, 0x3f, sizeof E); int n, m; cin >> n >> m; for(int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; sum += w; E[u][v] = E[v][u] = min(E[u][v], w); d[u]++, d[v]++; } for(int k = 1; k <= n; k++) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { E[i][j] = min(E[i][j], E[i][k] + E[k][j]); } } } if(m == 0) { cout << 0 << endl; return 0; } for(int i = 2; i <= n; i++) { if(E[1][i] == E[0][0] && d[i]) { cout << -1 << endl; return 0; } } int sta = 0; for(int i = 1; i <= n; i++) { if(d[i] % 2 == 0) sta += (1 << (i - 1)); } memset(dp,0x3f,sizeof dp); dp[sta] = 0; for(int i = 0; i < (1 << n); i++) { if((i & sta) == sta) { for(int j = 0; j < n; j++) { if(! ((i >> j) & 1)) for(int z = j + 1; z < n; z++) { if(!((i >> z) & 1)){ dp[i|(1<<j)|(1<<z)] = min(dp[i|(1<<j)|(1<<z)],dp[i] + E[j + 1][z + 1]); } } } } } cout<<dp[(1 << n) - 1] + sum<<endl; }
#include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <vector> #include <time.h> #include <string> #include <stack> #include <set> #include <map> #include <iostream> #include <bitset> #include <algorithm> using namespace std; #define MP make_pair #define PB push_back typedef long long LL; typedef pair<int, int> Pii; const int inf = 0x3f3f3f3f; const LL INF = (1uLL << 63) - 1; const LL mod = 1000000007; const int N = 150 + 5; const double Pi = acos(-1.0); const int maxn = 1e6 + 5; int E[21][21]; int d[21]; int sum = 0; bool vis[21]; int cnt = 0; int num[21]; int dfs(int cur) { if(cur == cnt)return 0; if(vis[cur]){ return dfs(cur + 1); } vis[cur] = 1; int res = inf; for(int i = 0; i < cnt; i++) { if(!vis[i]){ vis[i] = 1; res = min(res , E[num[cur]][num[i]] + dfs(cur + 1)); vis[i] = 0; } } vis[cur] = 0; return res; } int main() { #ifdef local freopen("in", "r", stdin); // freopen("w","w",stdout); #endif ios::sync_with_stdio(false); cin.tie(0); memset(E, 0x3f, sizeof E); int n, m; cin >> n >> m; for(int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; sum += w; E[u][v] = E[v][u] = min(E[u][v], w); d[u]++, d[v]++; } for(int k = 1; k <= n; k++) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { E[i][j] = min(E[i][j], E[i][k] + E[k][j]); } } } if(m == 0){ cout<<0<<endl; return 0; } for(int i = 2; i <= n; i++) { if(E[1][i] == E[0][0] && d[i]) { cout << -1 << endl; return 0; } } for(int i = 1; i <= n; i++) { 以上是关于WannaflyUnion每日一题的主要内容,如果未能解决你的问题,请参考以下文章