A.牛妹的游戏
Ramsey定理:人话解释任意六个人中要么至少三个人认识,要么至少三个不认识。
结论简要证明:
假设 666 个据点分别为 A,B,C,D,E,FA,B,C,D,E,FA,B,C,D,E,F那么在 A 连向其它据点的控制链中,必然至少有 333条链被同一方控制,不妨假设它们为 AB,AC,ADAB,AC,ADAB,AC,AD。如此一来只要 BC,BD,CDBC,BD,CDBC,BD,CD 中有任意一条链也被这一方控制,则可以形成控制区域;如果这三条链都没有被这一方控制,也就意味着它们都被对方控制了,则它们同样可以形成控制区域。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N=500010;
int n,m;
int e[10][10];
int main()
{IO;int T=1;cin>>T;while(T--){cin>>n>>m;memset(e,0,sizeof e);if(n>5){for(int i=1;i<=m;i++){int a,b;cin>>a>>b;}cout<<"yes\n";continue;}for(int i=1;i<=m;i++){int a,b;cin>>a>>b;e[a][b]=e[b][a]=1;}bool ok=0;for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)for(int k=j+1;k<=n;k++)if(e[i][j]&&e[j][k]&&e[k][i]||!e[i][j]&&!e[j][k]&&!e[k][i])ok=1;if(ok) cout<<"yes\n";else cout<<"no\n";}return 0;
}
B.病毒扩散
打表找规律,杨辉三角。
第四秒后扩张现象如下图
[1×14×16×14×11×14×16×24×31×46×14×31×64×11×41×1]\begin{bmatrix} 1×1&4×1&6×1&4×1&1×1\\4×1&6×2&4×3&1×4\\6×1&4×3&1×6\\4×1&1×4\\1×1 \end{bmatrix}⎣⎢⎢⎢⎢⎡1×14×16×14×11×14×16×24×31×46×14×31×64×11×41×1⎦⎥⎥⎥⎥⎤
好像不是那么明显,我们把乘号左边和右边的数分别拿出来
左边:[146414641641411]左边:\begin{bmatrix} 1&4&6&4&1\\4&6&4&1\\6&4&1\\4&1\\1 \end{bmatrix}左边:⎣⎢⎢⎢⎢⎡146414641641411⎦⎥⎥⎥⎥⎤
右边:[111111234136141]右边:\begin{bmatrix} 1&1&1&1&1\\1&2&3&4\\1&3&6\\1&4\\1 \end{bmatrix}右边:⎣⎢⎢⎢⎢⎡111111234136141⎦⎥⎥⎥⎥⎤
不难发现这两个矩阵的这些数和组合数(杨辉三角)有关
考虑位置为(x,y)(x,y)(x,y)时间是ttt的情况下:
左边的数Ctx+yC_{t}^{x+y}Ctx+y,右边的数Cx+yxC_{x+y}^xCx+yx那么最终答案就是Ctx+y×Cx+yxC_{t}^{x+y}×C_{x+y}^xCtx+y×Cx+yx
预处理阶乘和逆元即可O(1)O(1)O(1)得到每个位置的答案
我看不懂的官方证明转化
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N=5010;
const ll mod=998244353;
ll fact[N],infact[N];
ll qmi(ll a,ll b,ll p)
{ll res=1;while(b){if(b&1) res=res*a%p;b>>=1;a=a*a%p;}return res;
}
void init()
{fact[0]=infact[0]=1;for(int i=1;i<N;i++){fact[i]=fact[i-1]*i%mod;infact[i]=qmi(fact[i],mod-2,mod);}
}
int n;
int main()
{IO;int T=1;//cin>>T;init();while(T--){cin>>n;while(n--){int x,y,t;cin>>x>>y>>t;if(x+y>t) cout<<0<<'\n';else{ll res=1;res=res*fact[t]*infact[x+y]%mod*infact[t-x-y]%mod;res=res*fact[x+y]%mod*infact[x]%mod*infact[y]%mod;cout<<res<<'\n';}}}return 0;
}
C.牛牛染颜色
树形dp
状态表示:f(i,0/1)f_{(i,0/1)}f(i,0/1)表示选择/不选择uuu 这个节点后以 uuu 为根的子树的合法方案数。
状态转移:
若选择 uuu 这个节点,则子树内可以随便选点,每个子树独立乘法原理可得转移f(i,1)=∏j∈sonf(j,0)+f(j,1)f_{(i,1)}=\prod_{j\in son} f_{(j,0)}+f_{(j,1)}f(i,1)=∏j∈sonf(j,0)+f(j,1)
若不选择uuu 这个节点,则最多选择某一个子树,由加法原理可得转移f(i,0)=1+∑j∈son(f(j,0)+f(j,1)−1)f_{(i,0)}=1+\sum_{j\in son}(f_{(j,0)}+f_{(j,1)}-1)f(i,0)=1+∑j∈son(f(j,0)+f(j,1)−1)( f(i,0)f_{(i,0)}f(i,0)包含空集的方案,所以在枚举子树统计的时候每颗子树贡献的答案要减 111,但最后也要把空集的情况算上,还要加个111)
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1000010,mod=1e9+7;
int h[N],e[2*N],ne[2*N],idx;
ll f[N][2];
int n;
void add(int a,int b)
{e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void dfs(int u,int fa)
{f[u][0]=f[u][1]=1;for(int i=h[u];i!=-1;i=ne[i]){int j=e[i];if(j==fa) continue;dfs(j,u);f[u][1]=(f[u][1]*(f[j][0]+f[j][1]))%mod;f[u][0]=(f[u][0]+f[j][1]+f[j][0]-1)%mod;}
}
int main()
{IO;int T=1;//cin>>T;while(T--){cin>>n;memset(h,-1,sizeof h);for(int i=1;i<n;i++){int a,b;cin>>a>>b;add(a,b),add(b,a);}dfs(1,-1);cout<<(f[1][0]+f[1][1])%mod<<'\n';}return 0;
}
D. 牛牛的呱数
对于大数,基本上都是取模达到我们想要的目的。
由此可以把原串取模后的答案记录下来,并且记录它的长度(边权),和别的串相接的过程就类似从一个状态到另一个状态,只需要预处理10k%p10^k\%p10k%p的结果跑最短路即可。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef pair<int,int> pii;
const int N=210;
int ten[1000010];
struct node
{int val,len;
}a[N];
int dist[N],n,p;
bool st[N];
void dijkstra()
{memset(dist,0x3f,sizeof dist);priority_queue<pii,vector<pii>,greater<pii> >q;for(int i=1;i<=n;i++) {dist[a[i].val]=min(dist[a[i].val],a[i].len);q.push({a[i].len,a[i].val});}while(q.size()){int t=q.top().second;q.pop();if(st[t]) continue;st[t]=1;for(int i=1;i<=n;i++){int now=(t*ten[a[i].len]%p+a[i].val)%p;if(dist[now]>dist[t]+a[i].len){dist[now]=dist[t]+a[i].len;q.push({dist[now],now});}}}
}
int main()
{IO;int T=1;//cin>>T;while(T--){cin>>n>>p;ten[0]=1;for(int i=1;i<=1000000;i++) ten[i]=ten[i-1]*10%p;for(int i=1;i<=n;i++){string s;cin>>s;a[i].len=s.size();reverse(s.begin(),s.end());ll base=1;ll now=0;for(auto t:s){now=(now+base*(t-'0')%p)%p;base=base*10%p;}a[i].val=now%p;}dijkstra();if(dist[0]==0x3f3f3f3f) cout<<"-1\n";else cout<<dist[0]<<'\n';}return 0;
}
要加油哦~~