D - Decimal
题意:
询问\(\frac{1}{n}\)是否为有限小数。
思路:
拆质因子,看是不是只包含2和5即可,否则除不尽。
Code
#include <bits/stdc++.h> #define MP make_pair #define fi first #define se second #define sz(x) (int)(x).size() using namespace std; typedef long long ll; typedef pair<int, int> pii; const int N = 1e5 + 5; int t,n; int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef Local freopen("../input.in", "r", stdin); freopen("../output.out", "w", stdout); #endif cin>>t; while(t--){ cin>>n; while(n%2==0){ n/=2; } while(n%5==0){ n/=5; } if(n!=1)cout<<"Yes\n"; else cout<<"No\n"; } return 0; }
E - Escape
因为网上很多代码都有点问题,所以单独写了一下:传送门
F - Forest Program
题意:
给出一个仙人掌图(每条边最多在一个简单环中),可能不联通。
问有多少种删边方法能使得这个图变为森林。
思路:
显然对于环上的边我们至少删一条边,其它边随便删,所以关键就是找简单环。
一开始纠结点双什么的,魔改tarjan...
后面发现直接dfs找环就行,环长可以直接利用深度来求。
Code
#include <bits/stdc++.h> #define MP make_pair #define fi first #define se second #define sz(x) (int)(x).size() //#define Local using namespace std; typedef long long ll; typedef pair<int, int> pii; const int N = 1e5 + 5; const int MAXN=3e5+5,MAXM=1e6+5,MOD=998244353; struct Edge{ int v,next; }e[MAXM]; int n,m,u,v,head[MAXN],cnt,dep[MAXN]; ll ans=1,pw[500005]; bool vis[MAXN],ins[MAXN]; inline void addEdge(int u,int v){ e[++cnt] = {v,head[u]};head[u] = cnt; } void dfs(int u,int f){ ins[u]=vis[u]=1; dep[u] = dep[f] + 1; for(int i=head[u];i;i=e[i].next){ int v=e[i].v; if(v==f)continue; if(ins[v]){ ans = ans * (pw[dep[u]-dep[v]+1]-1+MOD)%MOD; m-=dep[u]-dep[v]+1; } if(vis[v])continue; dfs(v,u); } ins[u]=0; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); //cout << fixed << setprecision(20); #ifdef Local freopen("../input.in", "r", stdin); freopen("../output.out", "w", stdout); #endif pw[0]=1; for(int i=1;i<=500000;i++)pw[i]=pw[i-1]*2%MOD; cin>>n>>m; for(int i=1;i<=m;i++){ cin>>u>>v; addEdge(u,v);addEdge(v,u); } for(int i=1;i<=n;i++){ if(!vis[i])dfs(i,0); } cout<<ans*pw[m]%MOD<<'\n'; return 0; }
I - Invoker
似乎是直接暴力dp+模拟。
Code
#include <bits/stdc++.h> using namespace std; #define REP(i,a,b) for(register int i=(a);i<(b);i++) inline int calc(); #define MAXN 3*3*3+7 int dis[MAXN][MAXN]; bool vis[MAXN]; vector<int> pers[17]; inline int skilltoid(int a, int b, int c) { int k=(1<<(2*a))+(1<<(2*b))+(1<<(2*c)); #define F(x,y,z) ((1<<(2*x))+(1<<(2*y))+(1<<(2*z))) #define Q 0 #define W 1 #define E 2 switch(k) { case F(Q, Q, Q): return 1; case F(Q, Q, W): return 2; case F(Q, Q, E): return 3; case F(W, W, W): return 4; case F(Q, W, W): return 5; case F(W, W, E): return 6; case F(E, E, E): return 7; case F(Q, E, E): return 8; case F(W, E, E): return 9; case F(Q, W, E): return 10; } return -1; #undef F #undef Q #undef W #undef E } inline int id(int a,int b,int c) { return 3*3*a+3*b+c+1; } inline void test(int z) { const char x[]="QWE"; REP(a,0,3)REP(b,0,3)REP(c,0,3) if(z==id(a,b,c)) {printf("%c%c%c",x[a],x[b],x[c]);} } inline int chtoid(char x) { switch(x) { case 'Y': return 1; case 'V': return 2; case 'G': return 3; case 'C': return 4; case 'X': return 5; case 'Z': return 6; case 'T': return 7; case 'F': return 8; case 'D': return 9; case 'B': return 10; } return 0; } inline void genpers() { pers[0].push_back(0); REP(a,0,3)REP(b,0,3)REP(c,0,3) { int sid=skilltoid(a,b,c); pers[sid].push_back(id(a,b,c)); } } struct node{ int a,b,c; int l; }; queue<node> q; inline void gendis(int a,int b,int c) { memset(vis,0,sizeof vis); int nid; int mid=id(a,b,c); dis[0][mid]=3; vis[mid]=1; q.push((node){a,b,c,0}); dis[mid][mid]=0; while(!q.empty()) { node now=q.front(); q.pop(); REP(d,0,3) { nid=id(now.b,now.c,d); if(!vis[nid]) { q.push((node){now.b,now.c,d,now.l+1}); vis[nid]=1; dis[mid][nid]=now.l+1; } } } } char seq[100007]; int dp[2][9]; int main() { genpers(); REP(a,0,3)REP(b,0,3)REP(c,0,3){gendis(a,b,c);} scanf("%s", seq); int len=strlen(seq); int t=0, lst=0, now=0; REP(i,0,9) dp[t][i]=0; REP(i,0,len) { lst=now; t^=1; char ch=seq[i]; now=chtoid(ch); REP(k,0,pers[now].size()) { dp[t][k]=0x3f3f3f3f; int p; REP(j,0,pers[lst].size()) { //if(dp[t^1][j]+dis[pers[lst][j]][pers[now][k]]<=dp[t][k]) // test(pers[lst][j]), putchar('>'), //test(pers[now][k]), printf("%d\n", dis[pers[lst][j]][pers[now][k]]); dp[t][k]=min(dp[t][k],dp[t^1][j]+dis[pers[lst][j]][pers[now][k]]); } } //putchar('\n'); } int ans=0x7fffffff; REP(i,0,pers[now].size()) { ans=min(ans,dp[t][i]); } printf("%d\n", ans+len); return 0; }
J - MUV LUV EXTRA
题意:
给出一串数字,定义\(l\)为某个循环节的长度,\(p\)为循环节出现的总长度(直到某尾才行)。
一个循环节对答案的贡献为\(a\cdot p-b\cdot l\),问最大贡献是多少。
思路:
如果我们贪心来思考的话,\(p\)肯定越大越好,\(l\)肯定越小越好。所以基本思路就是找到一个最小循环节。
因为每次循环节要直至末尾,所以我们要找\(i\cdots n,1\leq i\leq n\)的所有最小循环节。
删除一个数的贡献不容易,就考虑添加,那么倒过来直接KMP即可。
Code
#include <bits/stdc++.h> #define MP make_pair #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() // #define Local using namespace std; typedef long long ll; typedef pair<int, int> pii; const int N = 1e7 + 5; ll a, b; char s[N], t[N]; int nxt[N]; void Get_next(char *s) { int j, L = strlen(s + 1); nxt[1] = j = 0; for(int i = 2; i <= L; i++) { while(j && s[i] != s[j + 1]) j = nxt[j]; if(s[i] == s[j + 1]) ++j; nxt[i] = j; } } void run() { cin >> (s + 1); int n = strlen(s + 1), m = 0; bool ok = 0; for(int i = 1; i <= n; i++) { if(s[i] == '.') { ok = 1; } else { if(ok == 0) continue; t[++m] = s[i]; } } n = m; reverse(t + 1, t + n + 1); Get_next(t); ll ans = -2666666666666666666; for(int i = 1; i <= n; i++) { int l = i - nxt[i], p = i; ans = max(ans, a * p - b * l); } cout << ans << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cout << fixed << setprecision(20); #ifdef Local freopen("../input.in", "r", stdin); freopen("../output.out", "w", stdout); #endif while(cin >> a >> b) run(); return 0; }
K - MUV LUV UNLIMITED
题意:
给出一颗以\(1\)为根的有根树,现在\(A,B\)在这颗树上玩博弈。
规则如下:每次一个人可以选择至少一个叶子结点进行删除,最后不能删除的人失败。
思路:
感觉挺有意思的一个题,定义“树枝边”为:从叶子结点往上,直到第一个分叉点的路径长度。
然后就有一个结论:
- 若存在一个长度为\(1\)的树枝边,那么此时先手必胜。
口胡证明
若目前为一条链的情况,显然多出一条树枝边结论成立; 假设现在为多条链的情况,假设原状态为必胜态,那么多出一条边不影响;若为必败态,可以直接去掉这条树枝边把必败状态留给对方。 若多处若干树枝边,不影响结论。所以当所有树枝边长度为\(2\)时,就时必败状态了。
现在我们已经知道树枝边小规模时的状态,那么接下来可以转换为一个石子博弈问题:给出多堆石子,每次可以选择任意堆,从上面取走一个石子,至少取一个石子,若一个人面临着存在石子数量为\(1\)的局面,就直接胜利。
这个博弈我们可以直接根据奇偶性来考虑,全为偶数时,后手有很大优势;否则,先手能将必输状态扔给对方。
代码如下:
Code
#include <bits/stdc++.h> #define MP make_pair #define fi first #define se second #define sz(x) (int)(x).size() #define all(x) (x).begin(), (x).end() // #define Local using namespace std; typedef long long ll; typedef pair<int, int> pii; const int N = 1e6 + 5; int n; int d[N], a[N]; std::vector<int> g[N]; void dfs(int u, int fa, int &sz) { if(d[u] > 1) return; ++sz; for(auto v : g[u]) { dfs(v, u, sz); } } void run() { cin >> n; for(int i = 1; i <= n; i++) d[i] = 0, g[i].clear(); for(int i = 1; i < n; i++) { int x; cin >> x; ++d[x]; g[i + 1].push_back(x); } int tot = 0; for(int i = 1; i <= n; i++) { if(d[i] == 0) { int x = 0; dfs(i, 0, x); a[++tot] = x; } } for(int i = 1; i <= tot; i++) { if(a[i] & 1) { cout << "Takeru" << '\n'; return; } } cout << "Meiya" << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cout << fixed << setprecision(20); #ifdef Local freopen("../input.in", "r", stdin); freopen("../output.out", "w", stdout); #endif int T; cin >> T; while(T--) run(); return 0; }
来源:博客园
作者:heyuhhh
链接:https://www.cnblogs.com/heyuhhh/p/11672234.html