Codeforces Round #460 (Div. 2) ABCDE题解
原文链接http://www.cnblogs.com/zhouzhendong/p/8397685.html
2018-02-01
$A$
题意概括
你要买$m$斤水果,现在有$n$个超市让你选择。
每个超市的水果价格是固定的。第$i$个超市的水果价格用两个整数$a_i和b_i$来表示。含义是$a_i$元可以买$b_i$斤。
问你买$m$斤水果最少花费多少钱。
题解
直接枚举超市,判断最少的花费就可以了。
代码
#include <cstring> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> using namespace std; const int N=5005; int n; double m,ans=1e100; int main(){ scanf("%d%lf",&n,&m); for (int i=1;i<=n;i++){ int a,b; scanf("%d%d",&a,&b); ans=min(ans,m*a/b); } printf("%.10lf",ans); return 0; }
$B$
题意概括
找第$k$个各个数位之和为 10 的正整数。($k<=10000$)
题解
从1开始暴搜即可。每次把各个数位加起来判断一下就可以了。实测$k=10000$的时候大约答案为一千万左右。
代码
#include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <cstdlib> using namespace std; int k,ans=0; bool check(int v){ int res=0; while (v){ res+=v%10,v/=10; if (res>10) break; } return res==10; } int main(){ scanf("%d",&k); while (k-=check(++ans)); printf("%d",ans); return 0; }
$C$
题意概括
给一个$n \times m$的矩阵,里面'.'表示空,'*'表示有人,问你有多少个不同的$1 \times k$的全空矩阵。
1<=n,m,k<=2000
题解
我们分每行每列分别枚举,每个前缀'.'大于等于k的格子贡献为1.
然而本题有坑点,不少$hacker$借此大赚一把。
当$k=1$的时候,答案要除以2!!!
代码
#include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <cstdlib> using namespace std; const int N=2005; int n,m,k; char g[N][N]; int main(){ scanf("%d%d%d",&n,&m,&k); for (int i=1;i<=n;i++) scanf("%s",g[i]+1); int ans=0; for (int i=1;i<=n;i++){ int cnt=0; for (int j=1;j<=m;j++){ if (g[i][j]=='.') cnt++; else cnt=0; if (cnt>=k) ans++; } } for (int i=1;i<=m;i++){ int cnt=0; for (int j=1;j<=n;j++){ if (g[j][i]=='.') cnt++; else cnt=0; if (cnt>=k) ans++; } } if (k==1) ans/=2; printf("%d",ans); return 0; }
$D$
题意概括
有一个有$n$个节点,$m$条边的有向图,每一个节点i上面有一个字母$a_i$。
定义一条路径的价值为经过的所有节点中遇到的出现次数最多的字母的出现次数。
现在问你价值最大的路径的价值。(如果价值为$\infty$,输出$-1$)
$ 1 <= n,m <= 300000 , 'a'<= a_i <= 'z' $
题解
首先考虑 $-1$ 的情况。
显然,只要有环就是 $-1$,所以这个可以实现判掉。
于是剩下来的就是一个$DAG$了。
那么显然,由于字母只有26个,那么我们只需要拓扑排序 + $DP$就可以了。
具体怎么DP看代码。
代码
#include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <cstdlib> using namespace std; const int N=300005,M=300005; struct Gragh{ int cnt,y[M],nxt[M],fst[N]; void clear(){ cnt=0; memset(fst,0,sizeof fst); } void add(int a,int b){ y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt; } }g; int n,m,v[N],vis[N]; int in[N],q[N],head,tail,dp[N][26]; char s[N]; bool dfs_round(int x,int mark){ if (vis[x]) return vis[x]==mark&&in[x]; vis[x]=mark; in[x]=1; for (int i=g.fst[x];i;i=g.nxt[i]) if (dfs_round(g.y[i],mark)) return 1; in[x]=0; return 0; } bool round(){ memset(vis,0,sizeof vis); memset(in,0,sizeof in); int mark=0; for (int i=1;i<=n;i++) if (!vis[i]) if (dfs_round(i,++mark)) return 1; return 0; } int main(){ scanf("%d%d%s",&n,&m,s+1); for (int i=1;i<=n;i++) v[i]=s[i]-'a'; g.clear(); for (int i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); g.add(a,b); } if (round()){ puts("-1"); return 0; } memset(dp,0,sizeof dp); memset(in,0,sizeof in); for (int i=1;i<=m;i++) in[g.y[i]]++; head=tail=0; for (int i=1;i<=n;i++) if (!in[i]) q[++tail]=i; int ans=0; while (head<tail){ int x=q[++head]; dp[x][v[x]]++; for (int i=0;i<26;i++) ans=max(ans,dp[x][i]); for (int i=g.fst[x];i;i=g.nxt[i]){ int y=g.y[i]; for (int j=0;j<26;j++) dp[y][j]=max(dp[y][j],dp[x][j]); if (!--in[y]) q[++tail]=y; } } printf("%d",ans); return 0; }
$E$
题意概括
问有多少个n满足以下条件:
$ 1<=n<=x $
$ n \cdot a^n \equiv b (mod \; p) $
输入$a b p x$,保证$p$是素数。
2 ≤ p ≤ 106 + 3, 1 ≤ a, b < p, 1 ≤ x ≤ 1012
题解
由于p为素数,根据费马小定理,$ a^k \equiv a^{k+(p-1)} (mod \; p) $
于是我们可以从$1$ ~ $p-1$枚举$n \bmod (p-1)$的值。
然后对于一个解$n\;mod\;(p-1) = i$,我们考虑到$a^n \equiv a^i (mod \; p )$, 所以,可以得到$n \equiv \frac{b}{a^i} (mod \; p)$
即$n \equiv b \times inv(a^i) (mod \; p)$
设$ x=i \; mod \; (p-1),\; y=b \times inv(a^i) \; mod \; p$,则有如下两个方程:
$n \equiv x\;(mod\;(p-1))$
$n \equiv y\;(mod\;p)$
这个讲道理有中国剩余定理(CRT)合并,但是实际上我们只需要瞎凑就可以了。
凑出来,$n\equiv -(p-1)\times y\; + \; p \times x (mod \; (p(p-1)))$
于是我们得到了关于$n$的一般形式,那么计算他的贡献就很轻松了(这个不讲了,直接看代码吧),总共$p-1$种$n$的形式,每个的贡献相加即答案。
代码
#include <cstring> #include <cmath> #include <cstdlib> #include <cstdio> #include <algorithm> using namespace std; typedef long long LL; const int P=1e6+10; LL a,b,p,x,inv[P]; LL Pow(LL x,LL y){ if (!y) return 1; LL xx=Pow(x,y/2); xx=xx*xx%p; if (y&1LL) xx=xx*x%p; return xx; } LL Inv(LL x){ return Pow(x,p-2); } int main(){ scanf("%I64d%I64d%I64d%I64d",&a,&b,&p,&x); for (LL i=1;i<p;i++) inv[i]=Inv(i); LL ans=0; for (LL i=1;i<p;i++){ LL y=b*inv[Pow(a,i)]%p; // n=y (mod p) // n=i (mod p-1) // n=up+y=v(p-1)+i // n=kp(p-1) - (p-1)*y + p*i LL mod=p*(p-1),n=(p*i%mod-(p-1)*y%mod+mod-1)%mod+1; if (n<=x) ans+=(x-n)/mod+1; } printf("%I64d",ans); return 0; }