还是先整理下题目
走格子
在平面上有n*n大小的正方形,定义正方形左下角坐标是(1,1),右下角坐标是(n,1)现在A君在左下角,他的初始方向是向右,他要在正方形内走m步当A君碰到边界或者已经走过的格子时,他便会逆时针转90°继续走,直到走完m步。现在给你两个整数n和m,请算出走完m步后A君的坐标。
dfs一下
const int maxn=3005;
int mp[maxn][maxn];
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1},n,m;
int judge(int x,int y)
{
if(x>=1&&y>=1&&x<=n&&y<=n)
{
if(mp[x][y]==0)return 1;
}
return 0;
}
int f=0;
void dfs(int x,int y,int d,int ans)
{
mp[x][y]=1;
if(ans>=m)
{
printf("%d %d\n",x,y);
f=1;
return;
}
int xx=x+dx[d];
int yy=y+dy[d];
if(judge(xx,yy)) dfs(xx,yy,d,ans+1);
else dfs(x,y,(d+1)%4,ans);
}
int main()
{
scanf("%d%d",&n,&m);
dfs(1,1,0,0);
return 0;
}
求值2
给出n求Ans
Ans = 0;
For(inti = 1; i <= n; i++)
For(int v = 0; v <= n; v++)
Ans = (Ans + C(i, v) * C(i, v)) % 998244353;
这道题需要公式推导一下,
1,C(n,1)+C(n,2)+...C(n,n)=2^n;
2,C(n,1)+2*C(n,2)+3*C(n,3)+....n*C(n,n)=n*2^(n-1);
3,C(a,0)C(b,n)+C(a,1)C(b,n-1)+...C(a,n)C(b,0)=C(a+b,n) , n=min(a,b);
4,(C(n,0)^2)+(C(n,1)^2)+...(C(n,n)^2)=C(2n,n)。
定理4是用3推出的,3是直接推下。具体证明看《概率论与数理统计教程》(第二版)茆诗松 30页课后题
跳格子
sum 个格子排成一排,每次可以往前跳 1-n 格,往回跳 1-m 格,而且在往回跳的时候只能跳在往前跳时踩过的格子。现在,在格子上跳,问跳到最后一个格子上最后又跳回第一个格子之前的方案数 mod 233333333。注意:只能一直向前跳,跳到最后一个格子,然后再往回跳,跳回第一个格子之前。
这道题我还是得继续琢磨琢磨。。。。
官方题解:
从最后一个格子跳回第一个格子之前可以看作是从一个格子之前跳到最后一个格子
所以题意就变成了
跳两次
第二次跳必须踩在第一次跳的格子上
则第二次跳的格子的集合必定是作为第一次跳的格子的子集
我们考虑枚举枚举第二次跳的距离i
搜索有第一次跳的长度为i的方案数vi
然后有递推式f[n]=f[n-1]*v1+f[n-2]*v2+..+f[n-m]*vm
递推即可
const int N=4e5+5;
const int M=15;
const int mod=233333333;
int f[M],dp[N];
int main()
{
int n,m,sum,T;
scanf("%d",&T);
while(T--){
memset(f,0,sizeof(f));
memset(dp,0,sizeof(dp));
scanf("%d%d%d",&sum,&n,&m);
f[0]=1;
for(int i=1;i<=m;i++){
for(int j=1;j<=i&&j<=n;j++){
f[i]=(f[i]+f[i-j])%mod;
}
}
dp[0]=1;
for(int i=1;i<=sum;i++){
for(int j=1;j<=m&&j<=i;j++){
dp[i]=(dp[i]+1ll*dp[i-j]*f[j]%mod)%mod;
}
}
printf("%d\n",dp[sum]);
}
return 0;
}
Educational Codeforces Round 45 (Rated for Div. 2) C.Bracket Sequences Concatenation Problem
题意:给出n组括号组合,定义')'+'('=')('。问有多少对stra+strb合法。
思路:处理每一行括号组合,遇到'('就+1,遇到')'就-1,当然还要用栈处理掉不合法的情况')(',就是排除无论如何都没法组合的情况,然后用map记录每个合法的组的值,最后找匹配就可以了。
map<ll,ll>mp1;
map<ll,ll>mp2;
map<ll,ll>::iterator it;
stack<ll>k;
ll n;
char s[300005];
int main()
{
ll len,t;
int flag=0;
mp2.clear();
mp1.clear();
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%s",s);
len=strlen(s);
t=0;
for(int j=0;j<len;j++)
{
if(s[j]=='(') k.push(1);
else if(s[j]==')')
{
if(!k.empty()) k.pop();
else t++;
}
}
if(t!=0&&!k.empty()) {while(!k.empty()) k.pop(); continue;}//此时无论是')('类似无论怎样都不合法
else if(t==0&&!k.empty()) mp1[k.size()]++;
else if(t!=0&&k.empty()) mp2[(-t)]++;
else if(t==0&&k.empty()) mp1[0]++;
//cout<<t<<" "<<k.empty()<<endl;
while(!k.empty()) k.pop();
}
ll ans=0;
for(it=mp1.begin();it!=mp1.end();it++)
{
if(it->first==0)
{
ll r=it->second;
ans=ans+r*r;
}
else
{
ll r=it->first;
ll q;
q=-r;
ll w=mp2[q];
ans=ans+w*(it->second);
}
}
cout<<ans<<endl;
}
零碎的整理图论,还是回来再专门整理汇总吧
还正在看,一边啃运筹学课本一边瞎看博客中
下面来自:https://blog.csdn.net/u013514182/article/details/42281479
求连通分量
int current_cc,cc[maxn],vis[maxn];
vector<int> g[maxn];
void dfs(int u)
{
vis[u]=1;cc[u]=current_cc;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!vis[v]) dfs(v);
}
}
void find_cc(int n)//求连通分量
{
current_cc=0,mem(vis,0);
for(int u=1;u<=n;u++) if(!vis[u]) { current_cc++;dfs(u); }
}
.判定一个图是否为二分图&&无向图构造二分图
二分图定义:对于无向图G=<V,E>,如果可以把点集分为互不相交的两部分,即X和Y=V-X,使得每一条边的其中一个端点在X中,另一个端点在Y中,则称该图是二分图
非连通图是二分图 <=> 每个连通分量都是是二分图
int color[maxn];
vector<int> g[maxn];
bool bipartite(int u){
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(color[v]==color[u]) return false;
if(!color[v]){
color[v]=3-color[u];
if(!bipartite(v)) return false;
}
}
return true;
}
bool judge_bipartite(){
for(int i=1;i<=n;i++)
if(!color[i]){
color[i]=1;
if(!bipartite(i)) return false;
}
return true;
}
求割点/割顶(cut_vertex/articulation vertex)和桥(bridge)
割点定义:删除该点后,原图的连通分量数增加。对于连通图,就是删除该点后原图不再连通的点。
桥的定义:删除该边后,原图的连通分量数增加。对于连通图,就是删除该边后原图不在连通的边。
int dfs_clock=0,low[maxn],pre[maxn],is_cut[maxn],is_bridge[maxn][maxn];
vector<int> g[maxn];
void dfs(int u,int fa){
low[u]=pre[u]=++dfs_clock;//u一开始最远返向边指向自己
int child=0;
for(int i=0;i<g[u].size();i++){
int v=g[u][i];
if(!pre[v]){
child++;//记录孩子个数
dfs(v,u);
low[u]=min(low[u],low[v]);//u子树(除u外)的反向边
if(low[v]>=pre[u]) is_cut[u]=1;//u是割点
if(low[v]>pre[u]) is_bridge[u][i]=1;//u出发的第i条边是桥
}
else if(pre[v]<pre[u]&&v!=fa) low[u]=min(low[u],pre[v]);//u自己的反向边
}
if(fa<0&&child==1) is_cut[u]=0;//对根节点进行特判
}
void find_cutvertex_bridge(int n){
mem(is_cut,0),mem(is_bridge,0),mem(pre,0);
for(int i=1;i<=n;i++) if(!pre[i]) dfs(i,-1);
}