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<<"*";elsecout<<".";}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;
}