2019 ccpc 秦皇岛
D
如果1/n是有限小数,不停乘以10,一定在有限次之后成为一个整数。
10的质因子只有2和5,只要保证分母的质因子只有2和5即可
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #define fo(i, l, r) for (long long i = l; i <= r; i++) #define fd(i, l, r) for (long long i = r; i >= l; i--) #define mem(x) memset(x, 0, sizeof(x)) #define ll long long #define ld double using namespace std; const int maxn = 150; const ll mod = 1e9 + 7; const double eps = 1e-9; ll read() { ll x = 0, f = 1; char ch = getchar(); while (!(ch >= '0' && ch <= '9')) { if (ch == '-') f = -1; ch = getchar(); }; while (ch >= '0' && ch <= '9') { x = x * 10 + (ch - '0'); ch = getchar(); }; return x * f; } int main() { int T,n; T=read(); while(T--){ n=read(); while(n%2==0)n/=2; while(n%5==0)n/=5; if(n>1){ printf("Yes\n"); }else{ printf("No\n"); } } return 0; }
F
仙人掌,环之间不相互影响,一个环至少删掉一条边,链无所谓,分别计算乘法原理合并
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #define fo(i, l, r) for (long long i = l; i <= r; i++) #define fd(i, l, r) for (long long i = r; i >= l; i--) #define mem(x) memset(x, 0, sizeof(x)) #define ll long long #define ld double using namespace std; const int maxn = 300500; const ll mod = 998244353; const double eps = 1e-9; ll read() { ll x = 0, f = 1; char ch = getchar(); while (!(ch >= '0' && ch <= '9')) { if (ch == '-') f = -1; ch = getchar(); }; while (ch >= '0' && ch <= '9') { x = x * 10 + (ch - '0'); ch = getchar(); }; return x * f; } vector<int> g[maxn]; int n,m; int d[maxn],rem; ll ans,pw[maxn*2]; void dfs(int u,int fa,int deep){ d[u] = deep; int v,sz=(int)g[u].size()-1; fo(i,0,sz){ v=g[u][i]; if(v==fa)continue; if(!d[v]) dfs(v,u,deep+1); else if(d[v]<d[u]){ ans=(ans*(pw[d[u]-d[v]+1]-1+mod))%mod; rem -= (d[u]-d[v]+1); } } } int main() { pw[0]=1;pw[1]=2; fo(i,2,500010) pw[i] = (pw[i-1]+pw[i-1])%mod; int u,v; while(scanf("%d%d",&n,&m)!=EOF){ ans=1; rem=m; fo(i,1,n){ d[i]=0; g[i].clear(); } fo(i,1,m){ u=read();v=read(); g[u].push_back(v); g[v].push_back(u); } fo(i,1,n){ if(!d[i]){ dfs(i,0,1); } } ans=(ans*pw[rem])%mod; printf("%lld\n",ans); } return 0; }
I
和之前做过的一个题很像,但是那个题需要贪心的性质为支撑,这个dp直接做就行了
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #define fo(i, l, r) for (long long i = l; i <= r; i++) #define fd(i, l, r) for (long long i = r; i >= l; i--) #define mem(x) memset(x, 0, sizeof(x)) #define ll long long #define ld double using namespace std; const int maxn = 100500; const ll mod = 998244353; const double eps = 1e-9; ll read() { ll x = 0, f = 1; char ch = getchar(); while (!(ch >= '0' && ch <= '9')) { if (ch == '-') f = -1; ch = getchar(); }; while (ch >= '0' && ch <= '9') { x = x * 10 + (ch - '0'); ch = getchar(); }; return x * f; } int n; int req[150][5]; char s[10][4]={"QQQ","QQW","QQE","WWW","QWW","WWE","EEE","QEE","WEE","QWE"}; char t[11] = "YVGCXZTFDB"; char a[maxn],b[maxn]; int dp[maxn][3][3][3],sum1[maxn][3][3],sum2[maxn][3],sum3[maxn],cnt[3]; int main() { fo(i,0,9){ fo(j,0,2){ if(s[i][j]=='Q')req[t[i]][0]++; if(s[i][j]=='W')req[t[i]][1]++; if(s[i][j]=='E')req[t[i]][2]++; } } while(scanf("%s",a+1)!=EOF){ n=strlen(a+1); int m = 0; fo(i,1,n){ if(a[i] != a[i-1]) b[++m] = a[i]; } swap(n,m); memset(dp,0x3f,sizeof(dp)); memset(sum1,0,sizeof(sum1)); memset(sum2,0,sizeof(sum2)); memset(sum3,0,sizeof(sum3)); int ans = mod; fo(i,1,n){ fo(t1,0,2){ fo(t2,0,2){ fo(t3,0,2){ cnt[0]=cnt[1]=cnt[2]=0; cnt[t1]++; cnt[t2]++; cnt[t3]++; if(cnt[0]!=req[b[i]][0]||cnt[1]!=req[b[i]][1]||cnt[2]!=req[b[i]][2])continue; dp[i][t1][t2][t3] = sum3[i-1]+3; if(sum1[i-1][t1][t2]) dp[i][t1][t2][t3] = min(dp[i][t1][t2][t3],sum1[i-1][t1][t2]+1); if(sum2[i-1][t1]) dp[i][t1][t2][t3] = min(dp[i][t1][t2][t3],sum2[i-1][t1]+2); if(!sum1[i][t2][t3] || (sum1[i][t2][t3] > dp[i][t1][t2][t3])){ sum1[i][t2][t3] = dp[i][t1][t2][t3]; } if(!sum2[i][t3] || (sum2[i][t3] > dp[i][t1][t2][t3])){ sum2[i][t3] = dp[i][t1][t2][t3]; } if(!sum3[i] || (sum3[i] > dp[i][t1][t2][t3])){ sum3[i] = dp[i][t1][t2][t3]; } if(i==n) ans=min(ans,dp[i][t1][t2][t3] + m); } } } } printf("%d\n",ans); } return 0; }
J
倒过来做kmp找循环节
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #define fo(i, l, r) for (long long i = l; i <= r; i++) #define fd(i, l, r) for (long long i = r; i >= l; i--) #define mem(x) memset(x, 0, sizeof(x)) #define ll long long #define ld double using namespace std; const int maxn = 10000500; const ll mod = 998244353; const double eps = 1e-9; ll read() { ll x = 0, f = 1; char ch = getchar(); while (!(ch >= '0' && ch <= '9')) { if (ch == '-') f = -1; ch = getchar(); }; while (ch >= '0' && ch <= '9') { x = x * 10 + (ch - '0'); ch = getchar(); }; return x * f; } int nxt[maxn]; void kmp_pre(char x[], int m, int next[]) { int i, j; j = next[0] =-1; i = 0; while (i < m) { while (-1 != j && x[i] != x[j]) j = next[j]; next[++i] = ++j; } } ll a, b,ans; char s[maxn], x[maxn]; int n, m; int main() { while (scanf("%lld%lld", &a, &b) != EOF) { scanf("%s", s + 1); n = strlen(s + 1); m = 0; fd(i, 1, n) { if (s[i] < '0' || s[i] > '9') break; x[++m] = s[i]; } kmp_pre(x+1,m,nxt); ans = a-b; fo(i,2,m){ ans=max(ans,a*i-b*(i-nxt[i])); } printf("%lld\n",ans); } return 0; }
A
直角三角形,就要看直角边在哪个点上,分两种情况讨论,然后围绕着直角点极角排序,找垂直的边。
#pragma GCC optimize(2) #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <set> #include <cmath> #include <queue> #include <map> #include <ctime> #define ll long long #define ld double #define lson rt << 1, l, m #define pi acos(-1) #define rson rt << 1 | 1, m + 1, r #define fo(i, l, r) for (int i = l; i <= r; i++) #define fd(i, l, r) for (int i = r; i >= l; i--) #define mem(x) memset(x, 0, sizeof(x)) #define eps 1e-7 using namespace std; const ll maxn = 4050; const ll mod = 998244353; ll read() { ll x = 0, f = 1; char ch = getchar(); while (!(ch >= '0' && ch <= '9')) { if (ch == '-') f = -1; ch = getchar(); }; while (ch >= '0' && ch <= '9') { x = x * 10 + (ch - '0'); ch = getchar(); }; return x * f; } struct Point { ll x, y; int isq,id; Point() {} Point(ll _x, ll _y) { x = _x; y = _y; } ll operator^(const Point &b) const { return x * b.y - y * b.x; } ll operator*(const Point &b) const { return x * b.x + y * b.y; } Point operator-(const Point &b) const { return Point(x - b.x, y - b.y); } Point operator+(const Point &b) const { return Point(x + b.x, y + b.y); } Point rotleft(){ return Point(-y,x); } Point rotright(){ return Point(y,-x); } int getfield(){ if(x>0&&y>=0)return 1; if(x<=0&&y>0)return 2; if(x<0&&y<=0)return 3; if(x>=0&&y<0)return 4; return 5; } } ns[maxn], tmp[maxn],qs[maxn], now; struct cmp { Point p; cmp(const Point &p0){p = p0;} bool operator()(const Point &aa,const Point &bb) { Point a = aa-p,b = bb-p; if(a.getfield() != b.getfield()){ return a.getfield() < b.getfield(); }else{ return (a^b)>0; } } }; int n, q; ll ans[maxn]; ll sum[maxn]; int main() { while (scanf("%d%d", &n, &q) != EOF) { mem(ans); fo(i, 1, n) { scanf("%lld%lld",&ns[i].x,&ns[i].y); ns[i].isq=0;ns[i].id=i; tmp[i]=ns[i]; } fo(i, 1, q) { scanf("%lld%lld",&qs[i].x,&qs[i].y); qs[i].isq=1;qs[i].id=i; now = qs[i]; sort(ns + 1, ns + 1 + n, cmp(now)); fo(j,1,n){ now=(ns[j]-qs[i]).rotleft(); now=qs[i]+now; int ret = upper_bound(ns+1,ns+1+n,now,cmp(qs[i])) - lower_bound(ns+1,ns+1+n,now,cmp(qs[i])); ans[i] += ret; } } fo(i,1,q){ ns[n+i]=qs[i]; } fo(i,1,n){ now = tmp[i]; sort(ns+1,ns+1+n+q,cmp(tmp[i])); fo(j,1,n+q){ if(!ns[j].isq&&ns[j].id!=now.id)sum[j]=sum[j-1]+1; else sum[j]=sum[j-1]; } fo(j,1,n+q){ if(!ns[j].isq)continue; now=(ns[j]-tmp[i]).rotleft(); now=tmp[i]+now; ans[ns[j].id] += sum[upper_bound(ns+1,ns+1+n+q,now,cmp(tmp[i]))-ns-1] - sum[lower_bound(ns+1,ns+1+n+q,now,cmp(tmp[i]))-ns-1]; now=(ns[j]-tmp[i]).rotright(); now=tmp[i]+now; ans[ns[j].id] += sum[upper_bound(ns+1,ns+1+n+q,now,cmp(tmp[i]))-ns-1] - sum[lower_bound(ns+1,ns+1+n+q,now,cmp(tmp[i]))-ns-1]; } } fo(i,1,q) printf("%lld\n",ans[i]); } return 0; }
E
给某些节点一个通过量的限制,从某些点出发、一些终点,可以向网络流的方向考虑,如何建图?
分析性质,假如说一个机器人从格点的一个边进入,再从某个边出,如果有人跟他反着来,则必然会逆着他走的路到第一行。
如果有人顺着它的路线走,那么会跟他走进同一个终点。
也就是说,如果这个节点,它拐弯了,那就只能一个机器人走一次。
如果它没拐弯,横着走过去之后,竖着走过去不会和原来横着走的路径有同样或者相反的结果,也就是能走两次。
拆点,把每个点拆成横竖两个点,相邻的恒竖相连,可以走2次,同一个点横竖相连,割这个边就说明在这个点放了转向器,只能走一次。
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <vector> #define fo(i, l, r) for (int i = l; i <= r; i++) #define fd(i, l, r) for (int i = r; i >= l; i--) #define mem(x) memset(x, 0, sizeof(x)) #define ll long long using namespace std; ll read() { ll x = 0, f = 1; char ch = getchar(); while (!(ch >= '0' && ch <= '9')) { if (ch == '-') f = -1; ch = getchar(); }; while (ch >= '0' && ch <= '9') { x = x * 10 + (ch - '0'); ch = getchar(); }; return x * f; } const int MAXN = 200010; //点数的最大值 const int MAXM = 1600010; //边数的最大值 const int INF = 0x3f3f3f3f; struct Edge { int to, next, cap, flow; } edge[MAXM]; //注意是 MAXM int tol; int head[MAXN]; int gap[MAXN], dep[MAXN], cur[MAXN]; void init() { tol = 0; memset(head,-1, sizeof(head)); } void addedge(int u, int v, int w, int rw = 0) { edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } int Q[MAXN]; void BFS(int start, int end) { memset(dep,-1, sizeof(dep)); memset(gap, 0, sizeof(gap)); gap[0] = 1; int front = 0, rear = 0; dep[end] = 0; Q[rear++] = end; while (front != rear) { int u = Q[front++]; for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if (dep[v] != -1) continue; Q[rear++] = v; dep[v] = dep[u] + 1; gap[dep[v]]++; } } } int S[MAXN]; int sap(int start, int end, int N) { BFS(start, end); memcpy(cur, head, sizeof(head)); int top = 0; int u = start; int ans = 0; while (dep[start] < N) { if (u == end) { int Min = INF; int inser; for (int i = 0; i < top; i++) if (Min > edge[S[i]].cap - edge[S[i]].flow) { Min = edge[S[i]].cap - edge[S[i]].flow; inser = i; } for (int i = 0; i < top; i++) { edge[S[i]].flow += Min; edge[S[i] ^ 1].flow -= Min; } ans += Min; top = inser; u = edge[S[top] ^ 1].to; continue; } bool flag = false; int v; for (int i = cur[u]; i != -1; i = edge[i].next) { v = edge[i].to; if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u]) { flag = true; cur[u] = i; break; } } if (flag) { S[top++] = cur[u]; u = v; continue; } int Min = N; for (int i = head[u]; i != -1; i = edge[i].next) if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) { Min = dep[edge[i].to]; cur[u] = i; } gap[dep[u]]--; if (!gap[dep[u]]) return ans; dep[u] = Min + 1; gap[dep[u]]++; if (u != start) u = edge[S[--top] ^ 1].to; } return ans; } int n,m,a,b; char mp[105][105]; inline int tran(int y,int x,int dir){ int t = (y-1)*m+x; if(dir) t+=n*m; return t; } inline bool jud(int y,int x){ return y>=1&&y<=n&&x>=1&&x<=m&&mp[y][x]=='0'; } int main() { int T=read(); while(T--){ init(); n=read();m=read();a=read();b=read(); fo(i,1,n){ scanf("%s",mp[i]+1); } fo(i,1,n){ fo(j,1,m){ if(!jud(i,j))continue; if(jud(i-1,j)) addedge(tran(i,j,0),tran(i-1,j,0),1); if(jud(i+1,j)) addedge(tran(i,j,0),tran(i+1,j,0),1); if(jud(i,j-1)) addedge(tran(i,j,1),tran(i,j-1,1),1); if(jud(i,j+1)) addedge(tran(i,j,1),tran(i,j+1,1),1); addedge(tran(i,j,0),tran(i,j,1),1); addedge(tran(i,j,1),tran(i,j,0),1); } } int u; fo(i,1,a){ u=read(); addedge(0,tran(1,u,0),1); } fo(i,1,b){ u=read(); addedge(tran(n,u,0),n*m*2+1,1); } if(sap(0,n*m*2+1,n*m*2+2)==a){ printf("Yes\n"); }else{ printf("No\n"); } } return 0; }