C 豆子
构造题
由构造公式知 第n级好豆子 = 第n-1级坏豆子^1
所以只需要构造一个豆子结构就行
第 i 级豆子 = 第 i 级豆子 第 i 级豆子 第 i 级豆子 第 i 级豆子 ^ 1 第i级豆子=\begin{aligned} 第i级豆子 && 第i级豆子 \\ 第i级豆子 && 第i级豆子 \verb|^| 1 \end{aligned} 第i级豆子=第i级豆子第i级豆子第i级豆子第i级豆子^1
预处理构造一下输出就行
#include<iostream>
using namespace std;
bool s[1100][1100];
bool d[6][6];
void init(int n)
{
s[1][1] = 1;
for(int i=2;i<=n;++i)
{
int x = (1<<(i-2));
for(int j=1;j<=x;++j)
for(int k=1;k<=x;++k)
{
s[j+x][k] = s[j][k];
s[j][k+x] = s[j][k];
s[j+x][k+x] = s[j][k]^1;
}
}
for(int i=3;i<6;++i)
for(int j=3;j<6;++j)
d[i][j] = 1;
}
void print(int x,int y,int u)
{
for(int i=0;i<6;++i)
{
for(int j=1;j<=y;++j)
for(int k=0;k<6;++k)
{
if((s[x][j]^u^d[i][k]))
cout<<"*";
else
cout<<".";
}
cout<<endl;
}
}
int main()
{
int n;cin>>n;
init(n);
int d = (1<<(n-1));
for(int i=1;i<=d;++i)
{
print(i,d,n&1^1);
}
return 0;
}
D 矩阵
直接两层bfs就行
#include<bits/stdc++.h>
using namespace std;
int dp[1010][1010][2];
int dr[] = {-1,0,1,0,0,1,0,-1};
queue<vector<int>>q;
string arr[1010];
int n,m;
void bfs(int x,int y,char f)
{
memset(dp,0x3f,sizeof(dp));
dp[x][y][f-'0'] = 0;
q.push({x,y,f-'0'});
while(!q.empty())
{
auto u = q.front();
q.pop();
for(int i=0;i<4;++i)
{
int nx = u[0] + dr[i<<1];
int ny = u[1] + dr[i<<1|1];
int nf = u[2]^1;
if(nx>=0 && nx<n && ny>=0 && ny<m)
{
int cost = 1;
if(arr[nx][ny]-'0' != nf)
cost = 2;
if(dp[nx][ny][nf]>dp[u[0]][u[1]][u[2]]+cost)
{
q.push({nx,ny,nf});
dp[nx][ny][nf]=dp[u[0]][u[1]][u[2]]+cost;
}
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;++i)
cin>>arr[i];
bfs(0,0,arr[0][0]);
cout<<min(dp[n-1][m-1][0],dp[n-1][m-1][1])<<endl;
}
/*
dp大概率会卡这组数据
2 10
1111101010
0101011111
*/
E 数数
由于数字不大,直接dp
用dp[i][j]表示长度为i时前缀和为j的方案数,显然只有 i ∣ j i|j i∣j(j被i整除)时才存在方案数
可以推出
d p [ i ] [ j ] = { 0 , j m o d i ≠ 0 ∑ k = j − m j d p [ i − 1 ] [ k ] , j m o d i = 0 dp[i][j] =\begin{cases} \ \ \ \ 0\ & , j\ mod\ i \ne 0 \\ \sum\limits^{j}_{k = j-m}dp[i-1][k] &, j\ mod\ i=0 \end{cases} dp[i][j]=⎩ ⎨ ⎧ 0 k=j−m∑jdp[i−1][k],j mod i=0,j mod i=0
这么遍历一次复杂度为 O ( n m l n ( n m ) ) O(nmln(nm)) O(nmln(nm)),由于dp中有很多0,所以可以优化一下
∑ k = j − m j d p [ i − 1 ] [ k ] = ∑ k = j − m + 1 i − 1 j i − 1 d p [ i − 1 ] [ k ∗ ( i − 1 ) ] \sum\limits^{j}_{k = j-m}dp[i-1][k] = \sum \limits^{\frac{j}{i-1}}_{k=\frac{j-m+1}{i-1}}dp[i-1][k*(i-1)] k=j−m∑jdp[i−1][k]=k=i−1j−m+1∑i−1jdp[i−1][k∗(i−1)]
那么复杂度就变成了 O ( n l n ( n m ) l n ( m ) ) O(nln(nm)ln(m)) O(nln(nm)ln(m))
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 1e9+7;
ll dp[6000000];
int main()
{
int n,m;cin>>n>>m;
for(int j=1;j<=m;++j)
dp[j] = 1;
for(int i=2;i<=n;++i)
{
for(int j=i*m;j>=i;j-=i)
{
dp[j] = 0;
for(int k = j/(i-1)*(i-1);k>=max(0,j-m);k-=i-1)
dp[j] = (dp[j]+dp[k])%mod;
}
}
int ans = 0;
for(int i=n;i<=n*m;i+=n)
ans = (ans+dp[i])%mod;
cout<<ans<<endl;
}
F 打牌
直接大力出奇迹,乱搞得了
通过阅读题目
而阿宁在手上有两张相同的牌,第三张不同的牌时,阿宁在相同的牌中等概率随机挑一张交给下家。其它情况阿宁也是等概率随机挑选。
分析会发现阿宁的行为是确定的。即如果此时没有人win,阿宁就会把手中最多的牌发出去。所以在没有剪枝的情况下复杂度应该为 O ( 4 n ) O(4^n) O(4n)
说实话这游戏想长时间不赢其实很难的,阿宁的操作保证在多轮操作后他手上至少会有两种手牌,所以说阿宁一直处于听牌的状态,“只要能拿到那张牌……”“不好意思,和!”,
然后考虑如果其中一个人有三张的情况,假设为aaa,另外两人就是bbc,ccb。如果aaa是阿宁上家,阿宁就赢了。
下家(A)为aaa的时候,此时
-
阿宁:bbc
-
A:aaa
-
B: ccb
阿宁打b,A打a,如果B不打b就赢了,因此想要游戏继续下去就得打b,因此就变成
-
阿宁:bbc
-
A:aab
-
B: cca
考虑大伙都有两张牌的情况,会发现b手上至少存在一张能让阿宁赢的牌,阿宁打出去的牌必然是a需要的牌,阿宁手上有的牌ab都有(都可以用反证法证明)。用字母表示当前情况
-
阿宁:aab
-
A:bbc/cca
-
B: cca/bbc
第一种情况{aab,cca,bbc}:
只有一种打法能让游戏继续下去,那就是阿宁打出A,A打出c,B打出a,此时会变成{aab,abb,ccc}情况。根据上面的分析,此时阿宁必赢
第二种情况{aab,cca,bbc}:
阿宁打出a,B为了阿宁不赢得打出b,A为了B不赢得打出c,此时变成{bba,aac,ccb}变成了必赢态
分析了一大轮,就会发现,在有限步内必有人会赢,而且这个有限步甚至不会超过5步。
所以这题直接暴力dfs就完事了,甚至不用剪枝。乱搞就行了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e9+7;
ll sp[3][3];
ll now[3][3];
map<char,int>mp;
ll qpow(ll a,ll b)
{
ll ret = 1;
while(b)
{
if(b&1) ret = ret*a%mod;
a = a*a%mod;
b>>=1;
}
return ret;
}
ll dfs(int n)
{
for(int i=0;i<3;++i)
if(sp[i][0]*sp[i][1]*sp[i][2])
return i==0;
if(!n)return 0;
ll ret = 0;
int mx = 0;
if(sp[0][1]>sp[0][mx]) mx = 1;
if(sp[0][2]>sp[0][mx]) mx = 2;
for(int i=0;i<3;++i)
{
if(!sp[1][i])continue;
for(int j=0;j<3;++j)
{
if(!sp[2][j])continue;
ll p = 1ll*sp[1][i]*sp[2][j]*qpow(9,mod-2)%mod;
sp[0][mx]--;sp[1][mx]++;
sp[1][i]--;sp[2][i]++;
sp[2][j]--;sp[0][j]++;
ret = (ret+dfs(n-1)*p%mod)%mod;
sp[0][mx]++;sp[1][mx]--;
sp[1][i]++;sp[2][i]--;
sp[2][j]++;sp[0][j]--;
}
}
return ret;
}
int main()
{
mp['w'] = 0;mp['i'] = 1;mp['n'] = 2;
int n;cin>>n;
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
{
char c;cin>>c;
sp[i][mp[c]]++;
}
ll ans = dfs(n);
cout<<ans<<endl;
}