5931 传递
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 71 Accepted Submission(s): 33
Problem Description
我们称一个有向图G是
传递的,当且仅当对任意三个不同的顶点a,,若G中有 一条边从a到b且有一条边从b到c ,则G中同样有一条边从a到c。
我们称图G是一个 竞赛图,当且仅当它是一个有向图且它的基图是完全图。换句 话说,将完全图每条边定向将得到一个竞赛图。
下图展示的是一个有4个顶点的竞赛图。
现在,给你两个有向图P = (V, E
p![]()
)和Q = (V,
E
e![]()
),满足:
1. E
P![]()
与
E
e![]()
没有公共边;
2. (V, E
p
⋃E
e![]()
)是一个竞赛图。
你的任务是:判定是否P,Q同时为传递的。
我们称图G是一个 竞赛图,当且仅当它是一个有向图且它的基图是完全图。换句 话说,将完全图每条边定向将得到一个竞赛图。
下图展示的是一个有4个顶点的竞赛图。

现在,给你两个有向图P = (V, E
1. E
2. (V, E
你的任务是:判定是否P,Q同时为传递的。
Input
包含至多20组测试数据。
第一行有一个正整数,表示数据的组数。
对于每组数据,第一行有一个正整数n。接下来n行,每行为连续的n个字符,每 个字符只可能是’-’,’P’,’Q’中的一种。
∙
如果第i行的第j个字符为’P’,表示有向图P中有一条边从i到j;
∙
如果第i行的第j个字符为’Q’,表示有向图Q中有一条边从i到j;
∙
否则表示两个图中均没有边从i到j。
保证1 <= n <= 2016,一个测试点中的多组数据中的n的和不超过16000。保证输入的图一定满足给出的限制条件。
第一行有一个正整数,表示数据的组数。
对于每组数据,第一行有一个正整数n。接下来n行,每行为连续的n个字符,每 个字符只可能是’-’,’P’,’Q’中的一种。
∙
∙
∙
保证1 <= n <= 2016,一个测试点中的多组数据中的n的和不超过16000。保证输入的图一定满足给出的限制条件。
Output
对每个数据,你需要输出一行。如果P! Q都是传递的,那么请输出’T’。否则, 请输出’N’ (均不包括引号)。
Sample Input
4 4 -PPP --PQ ---Q ---- 4 -P-P --PQ P--Q ---- 4 -PPP --QQ ---- --Q- 4 -PPP --PQ ---- --Q-
Sample Output
T N T NHint在下面的示意图中,左图为图为Q。注:在样例2中,P不是传递的。在样例4中,Q不是传递的。 ![]()
Source
三记录dfs-----记录下本节点和父节点以及父父节点-.-然后判断----时间复杂度(n*n)
代码:
#include<cstdio>
#include<cstring>
char ch[2100][2100];
bool guo[2100];
bool fafe;
int n;
void dfs(int ff,int f,int x)
{
if (!fafe) return ;
if (ff!=-1&&f!=-1)
{
// printf("%d %d %d %d\n",ff,f,x,guo[x]);
if (ch[ff][f]==ch[f][x]&&ch[ff][f]!=ch[ff][x])
{
fafe=false;
return ;
}
}
// else
// printf("%d %d %d %d 999\n",ff,f,x,guo[x]);
if (guo[x]) return ;
// printf("guo\n");
guo[x]=true;
if (!x)
{
for (int j=0;j<n;j++)
if (ch[0][j]!='-')
dfs(f,x,j);
}
else
{
for (int j=0;j<n;j++)
{
// printf("%d %c 666\n",j,ch[x][j]);
if (ch[x][j]!='-')
dfs(f,x,j);
}
}
}
int main()
{
int t;scanf("%d",&t);
while (t--)
{
scanf("%d",&n);
fafe=true;
for (int i=0;i<n;i++)
scanf("%s",ch[i]);
memset(guo,false,sizeof(guo));
dfs(-1,-1,0);
if (fafe)
printf("T\n");
else
printf("N\n");
}
return 0;
}
5965 扫雷
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 98 Accepted Submission(s): 28
Problem Description
扫雷游戏是晨晨和小璐特别喜欢的智力游戏,她俩最近沉迷其中无法自拔。
该游戏的界面是一个矩阵,矩阵中有些格子中有一个地雷,其余格子中没有地雷。 游戏中,格子可能处于己知和未知的状态。如果一个己知的格子中没有地雷,那么该 格子上会写有一个一位数,表示与这个格子八连通相邻的格子中地雷总的数量。
现在,晨晨和小璐在一个3行N列(均从1开始用连续正整数编号)的矩阵中进 行游戏,在这个矩阵中,第2行的格子全部是己知的,并且其中均没有地雷;而另外 两行中是未知的,并且其中的地雷总数量也是未知的。
晨晨和小璐想知道,第1行和第3行有多少种合法的埋放地雷的方案。
该游戏的界面是一个矩阵,矩阵中有些格子中有一个地雷,其余格子中没有地雷。 游戏中,格子可能处于己知和未知的状态。如果一个己知的格子中没有地雷,那么该 格子上会写有一个一位数,表示与这个格子八连通相邻的格子中地雷总的数量。
现在,晨晨和小璐在一个3行N列(均从1开始用连续正整数编号)的矩阵中进 行游戏,在这个矩阵中,第2行的格子全部是己知的,并且其中均没有地雷;而另外 两行中是未知的,并且其中的地雷总数量也是未知的。
晨晨和小璐想知道,第1行和第3行有多少种合法的埋放地雷的方案。
Input
包含多组测试数据,第一行一个正整数T,表示数据组数。
每组数据由一行仅由数字组成的长度为N的非空字符串组成,表示矩阵有3行N 列,字符串的第i个数字字符表示矩阵中第2行第i个格子中的数字。
保证字符串长度N <= 10000,数据组数<= 100。
每组数据由一行仅由数字组成的长度为N的非空字符串组成,表示矩阵有3行N 列,字符串的第i个数字字符表示矩阵中第2行第i个格子中的数字。
保证字符串长度N <= 10000,数据组数<= 100。
Output
每行仅一个数字,表示安放地雷的方案数mod100,000,007的结果。
Sample Input
2 22 000
Sample Output
6 1
Source
直接枚举第一列-----取模请看仔细------------
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
LL ans,s,mod;
char ch[20100];
int shu[20100];
int p[20100];
int c[3];
int se(int x)
{
if (x>2||x<0)
return false;
return true;
}
void slove()
{
scanf("%s",ch);
int n=strlen(ch);
c[0]=c[2]=1;
c[1]=2;
for (int i=0;i<n;i++)
shu[i]=ch[i]-'0';
if (n==1)
{
if (se(shu[0]))
printf("%d\n",c[shu[0]]);
else
printf("0\n");
return ;
}
ans=0;
for (int i=0;i<3;i++)
{
p[0]=i;
s=c[i];
for (int j=1;j<n;j++)
{
if (j==1)
p[1]=shu[0]-p[0];
else
p[j]=shu[j-1]-p[j-1]-p[j-2];
if (!se(p[j]))
{
s=0;
break;
}
// printf("%lld %d %d\n",s,p[j],c[p[j]]);
s=(s*c[p[j]])%mod;
// printf("%lld\n",s);
}
if (p[n-1]+p[n-2]==shu[n-1])
ans=(ans+s)%mod;
// printf("%d %lld\n",i,ans);
}
printf("%lld\n",ans);
}
int main()
{
int t;mod=100000007;
scanf("%d",&t);
while (t--)
slove();
return 0;
}
5968 异或密码
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 51 Accepted Submission(s): 29
Problem Description
晨晨在纸上写了一个长度为N的非负整数序列{
a
i![]()
}。对于这个序列的一个连续子序列{
a
l
,a
l+1
,…,a
r![]()
}晨晨可以求出其中所有数异或的结果
a
l
xora
l+1
xor...xora
r![]()
其 中xor表示位异或运算,对应C、C++、 Java等语言中的^运算。
小璐提出了M个询问,每个询问用一个整数 x
i![]()
描述。
对于每个询问,晨晨需要找到序列{ a
i![]()
}的所有连续子序列,求出每个子序列异或的结果,找到所有的结果中与
x
i![]()
之差的绝对值最小的一个,并告诉小璐相应子序列的长度。
若有多个满足条件的连续子序列,则告诉小璐这些子序列中最长的长度。
小璐提出了M个询问,每个询问用一个整数 x
对于每个询问,晨晨需要找到序列{ a
若有多个满足条件的连续子序列,则告诉小璐这些子序列中最长的长度。
Input
包含多组测试数据,第一行一个正整数T,表示数据组数。
每组数据共两行。
第一行包含N+1个非负整数。其中第一个数为N,表示序列的长度;接下来N 个数,依次描述序列{ a
i![]()
}中的每个数。
第二行包含M+1个整数。其中第一个数为M,表示询问的个数;接下来M个数 x
i![]()
,每个数对应题目描述中的一个询问。
保证 1 <= N <= 100,1 <= M <= 100, a
i![]()
<= 1024,|
x
i![]()
| <= 1024,数据组数 <= 100。
每组数据共两行。
第一行包含N+1个非负整数。其中第一个数为N,表示序列的长度;接下来N 个数,依次描述序列{ a
第二行包含M+1个整数。其中第一个数为M,表示询问的个数;接下来M个数 x
保证 1 <= N <= 100,1 <= M <= 100, a
Output
对于每组数据输出M + 1行。前M行对应晨晨M个询问的回答,第M + 1行为空行
Sample Input
2 2 1 1 2 0 2 3 1 2 4 3 10 5 1
Sample Output
2 1 3 2 1
Source
排序+二分
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
using namespace std;
int a[120],n,kp;
struct node{
int length,shu;
}pp[60000];
bool cmp(node xx,node yy)
{
if (xx.shu!=yy.shu)
return xx.shu<yy.shu;
return xx.length>yy.length;
}
void ss()
{
kp=0;
for (int i=1;i<=n;i++)
{
int ll=1;
int x=a[i];
pp[kp].length=ll;
pp[kp++].shu=x;
for (int j=i+1;j<=n;j++)
{
x^=a[j];
ll++;
pp[kp].length=ll;
pp[kp++].shu=x;
}
}
sort(pp,pp+kp,cmp);
return ;
}
int seach(int x)
{
int l=0,r=kp-1,m;
int ans=0;
while (l<=r)
{
m=(l+r)>>1;
if (pp[m].shu<x)
{
l=m+1;
ans=m;
}
else
r=m-1;
}
return ans;
}
void slove()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
ss();
int m,x,ans;
scanf("%d",&m);
while (m--)
{
scanf("%d",&x);
int p=seach(x);
if (pp[p].shu>=x)
{
printf("%d\n",pp[p].length);
}
else
{
if (p==kp-1)
{
ans=pp[p].length;
for (int i=p-1;i>=0&&pp[i].shu==pp[p].shu;i--)
ans=pp[i].length;
printf("%d\n",ans);
}
else
{
if (x-pp[p].shu<pp[p+1].shu-x)//左边近
{
ans=pp[p].length;
for (int i=p-1;i>=0&&pp[i].shu==pp[p].shu;i--)
ans=pp[i].length;
}
else if (x-pp[p].shu>pp[p+1].shu-x)//右边近
{
ans=pp[p+1].length;
}
else//两边一样
{
ans=pp[p+1].length;
for (int i=p;i>=0&&pp[i].shu==pp[p].shu;i--)
if (pp[i].length>ans)
ans=pp[i].length;
}
printf("%d\n",ans);
}
}
}
printf("\n");
}
int main()
{
int t;scanf("%d",&t);
while (t--)
slove();
return 0;
}
最大的位或
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 87 Accepted Submission(s): 53
Problem Description
B君和G君聊天的时候想到了如下的问题。
给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大。
其中|表示按位或,即C、 C++、 Java中的|运算。
给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大。
其中|表示按位或,即C、 C++、 Java中的|运算。
Input
包含至多10001组测试数据。
第一行有一个正整数,表示数据的组数。
接下来每一行表示一组数据,包含两个整数l,r。
保证 0 <= l <= r <= 10
18![]()
。
第一行有一个正整数,表示数据的组数。
接下来每一行表示一组数据,包含两个整数l,r。
保证 0 <= l <= r <= 10
Output
对于每组数据输出一行,表示最大的位或。
Sample Input
5 1 10 0 1 1023 1024 233 322 1000000000000000000 1000000000000000000
Sample Output
15 1 2047 511 1000000000000000000
Source
-.-画出 l , r 的二进制=--可以用 itoa函数()---
然后就会发现-.-从第一个不一样的位置----再往下---有0的地方一定可以补为1----------
代码:
</pre><pre name="code" class="cpp">#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
int main()
{
int t;scanf("%d",&t);
int a,ll[70],rr[70];
LL l,r,ans;
while (t--)
{
scanf("%lld%lld",&l,&r);
memset(ll,0,sizeof(ll));
memset(rr,0,sizeof(rr));
a=0;
while (l)
{
ll[a++]=l%2;
l/=2;
}
a=0;
while (r)
{
rr[a++]=r%2;
r/=2;
}
ans=0;
for (int i=65;i>=0;i--)
{
ans*=2;
ans+=rr[i];
if (ll[i]<rr[i])
{
for (int j=i-1;j>=0;j--)
ans=ans*2+1;
break;
}
}
printf("%lld\n",ans);
}
return 0;
}