A 被诅咒的WWT
题目描述
WWT因为过于可爱被一个邪恶的巫师施了魔咒,将WWT变成了一维的,并将他放到了一根坐标轴的坐标原点上,巫师的魔咒极其强大,WWT需要在坐标轴上移动十二步,且每一步只能移动X,Y,Z的距离。可以选择向左还是向右移动。
也就是说,WWT被巫师变成了一个在坐标轴上移动的棋子。巫师想玩一个游戏,进行q次询问,每次询问为一个点O,问WWT是否能正好在第12步到达该点O。如果能,输出YES,巫师是个奇怪的人,他又施巫术,移动了WWT的位置,使下一次询问的出发点变成了另外的一个点,这一次走12步的距离等于下一次出发点到原点的距离,值得注意的是巫师是个右撇子,每次都将WWT放在坐标轴右边。如果无法到达,则输出NO,且下一次出发点回到坐标轴原点。
输入描述:
第一行输入三个数X,Y,Z,0<=X,Y,Z<=1000。
第二行输入一个正整数q次 q<=10000
接下来的q行输入q次一个点O,-109<=O<=109
输出描述:
对于每次询问输出一行YES或NO
全部枚举出来路径。
对set的使用。
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
typedef long long ll;
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
ll c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
set<ll> s[13];
int main(void)
{
ll x,y,z;cin>>x>>y>>z;
s[0].insert(0);
for(int i=1;i<=12;i++){
for(set<ll>::iterator it=s[i-1].begin();it!=s[i-1].end();it++){
s[i].insert(*it+x);
s[i].insert(*it-x);
s[i].insert(*it+y);
s[i].insert(*it-y);
s[i].insert(*it+z);
s[i].insert(*it-z);
}
}
ll st=0,en;
int q;cin>>q;
while(q--){
cin>>en;
ll d;
d=en-st;
if(s[12].count(d)){
cout<<"YES"<<endl;
st=abs(d);
}
else{
cout<<"NO"<<endl;
st=0;
}
}
return 0;
}
C 始战
题目描述
天地不仁,以万物为刍狗。
东汉末年,群雄并起。十八路诸侯各自为战,为得一地一城,大肆征战,民众死伤无数。
诸葛亮密如神鬼,疾如风雷。进不可挡,退不可追。昼不可攻,夜不可袭。多不可敌,少不可欺。前后应会,左右指挥。移五行之性,变四时之令。
神人也。
现,亮得诸侯割据图。亮根据此图,预测第一战将会在何处爆发。
此图由n**m个单位组成,图中有n个诸侯的根据地所在地,每个诸侯只会在第一天都会向自己根据地的上下左右方向霸占土地。当两个诸侯霸占到同一块土地时,那么此两诸侯就会开战。现问第一场战役将会在何处爆发!
注意:此土地被霸占的前提条件是在这一天还未被别的诸侯霸占,如果已经被别的诸侯霸占了,那么他就无法霸占了,当然也不会开战,因为谁先到,就是谁的土地。但是如果这块土地,是一起到达的,那么就会开战。
输入描述:
多组输入
n,m表示此图由n行m列组成 (1<= n,m<= 100),左上角的坐标是(1,1).
下跟n行m列矩阵,矩阵由*和#组成,一个#代表着一个诸侯,*代表此土地待征服。 保证割据图中最多只有十八位诸侯,最少没有诸侯。
输出描述:
输出第一场战争的(x,y)坐标
如果不会爆发战争,请输入-1.
如果多个地方同时爆发第一场战争,那么请先按x排序,再按y排序,依次输出。
如果爆发战争输出格式为:
1 2
2 5
此表示第一场战争将在(1,2)和(2,5)两个点爆发。
反过来找嘛!找到空地,如果有多个诸侯要它,那就打架。
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
typedef long long ll;
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
ll c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
struct node
{
int x,y;
};
queue<node> q;
int main(void)
{
int n,m;
while(cin>>n>>m){
char a[105][105]={0};
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]=='*'){
int num=0;
if(a[i-1][j]=='#') num++;
if(a[i][j+1]=='#') num++;
if(a[i+1][j]=='#') num++;
if(a[i][j-1]=='#') num++;
if(num>1){
node k;
k.x=i,k.y=j;
q.push(k);
}
}
}
}
if(q.empty())cout<<-1<<endl;
else{
while(!q.empty()){
node k=q.front();
q.pop();
cout<< k.x <<" "<< k.y <<endl;
}
}
}
return 0;
}
D 秒速五厘米
题目描述
樱花飘落的速度,每秒五厘米。
动漫《秒速五厘米》中,明里曾在信中写道“我家附近有棵很大的樱花树,到了春天,那棵树上的花瓣,大概也会以每秒五公分的速度飘落,而我则在想,要是能和贵树一起迎接春天的来临该有多好啊。”
来年春天,他们没能像约定那样一起迎接春天的到来,看樱花飘落。
//哇!多美妙的一段话啊!
但有一个魔法,可以让他们有m秒的时间一起看樱花飘落,樱花树上有n朵樱花,每朵樱花都有一个高度a[i],樱花飘落的速度为v,樱花只能一朵一朵的飘落,如果某朵樱花飘落的时间不是整数,则那朵樱花飘落所需的时间要向上取整,即,若两朵樱花的高度都为7,飘落的速度为2,则两朵樱花飘落的时间为8,现在你可以控制樱花飘落的速度v,当v为何值时才能使所有的樱花在m秒的时间内全部飘落且v的值要尽可能小。
输入描述:
第一行输入两个正整数n和m(1<=n<=m<=2000000)
第二行输入n个正整数a[i](1<=a[i]<=10000000),分别指的是每朵樱花的高度
输出描述:
输出一个正整数v,代表樱花最合适的速度
二分出速度,然后遍历算出时间,看是否符合,然后最后算出最小时间
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
typedef long long ll;
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
ll c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
ll a[2000005];
ll n,m;
bool check(int x)
{
ll num=0;//需要的时间
for(int i=n;i>=1;i--){
num+=ceil((double)a[i]/x);
if(num>m) return 0;//如果时间比超出m就不行,时间需要向下取,则速度要变大
}
return 1;
}
int main(void)
{
cin>>n>>m;
ll l=1,r=0;
for(int i=1;i<=n;i++){
a[i]=read();
r=max(r,a[i]);
}
sort(a+1,a+1+n);
while(l<r){
int mid=(l+r)/2;
if(check(mid)){
r=mid;//速度变小
}
else l=mid+1;
}
cout<<l<<endl;
return 0;
}
F 陪你去流浪,踏遍那四海八荒
题目描述
巫山老伯一直想去远方流浪,踏遍四海八荒,攀登五岳珠峰!问世间情为何物,只教天若有情天亦老,人间正道是沧桑!
今日,巫山老伯再启程,去那北海极地,寻同道中人,看绝世美景。叹息,憾息。
巫山老伯,有一神秘法宝,助他踏遍四海,早寻同道中人,安看万世流景。此神秘法宝,极大的减轻了旅途中的负担。此神秘法宝,体积极小,外形堪似那古埃及的奇迹之做——金字塔。第一层可放容量为1的物件,第2层,可放容量不超过2的阶层的物件,第3层,可放容量不超过3的阶层的物件,第n层,可放容量不超过n的阶层的物件。以此类推 于是而已。
还有二件神秘宝物,可助他收藏旅途所收获之点点滴滴。
一为,万生药水;二为,万物归一。
万生药水,可以成倍复制那外形看似那金字塔的神秘法宝(例如:有n个神秘法宝,则可复制出2*n个神秘法宝)。
万物归一,可把多个神秘法宝归为一个神秘法宝,且体积会相应扩大,除第一层外其他所有层的容量都会变成相应层容量的和。
解释:如果有3个3层的神秘法宝,那么用了一个万物归一之后,变成的新的神秘法宝的容积将为(1+2!+2!+2!+3!+3!+3!)。
同时,万生药水和万物归一,巫山老伯是可以随便用的,但是要保证在最后一定要合成一个神秘法宝,同时要使容积是最大的(求模之前最大),不能同时带着多个神秘法宝行走于江湖。
例如:
巫山老伯此次出行带有,一个有3层的神秘法宝,2瓶万生药水,2瓶万物归一。那么此次出行巫山老伯最多能装(1+2! + 2! + 2! + 2! + 3! + 3! + 3! +3!)的容量物品。
解释:3层神秘法宝 可装容量为(1+2!+3!),用一瓶万生药水可装容量变成(1+2!+3!)+(1+2!+3!),在用一瓶万物归一则可装容量变为
(1+2!+2!+3!+3!);在用一瓶万生药水,可装容量变为(1+2!+2!+3!+3!)+(1+2!+2!+3!+3!),在用一瓶万物归一药水,可装容量变为
(1+2!+2! + 2!+2!+3!+3!+3!+3!)。
同时,巫山老伯为了保证神秘法宝过大,他会将每一层的容积对mod=3777105087进行取余(只要当前容积一大于mod,就进行取余)。然后重新得到每一层的容积。
输入描述:
多组输入
第一行输入n 表示初始神秘法宝是多少层的 (1<= n<=1e15)
第二行 输入 x 和 y 分别表示x瓶万生药水,y瓶万物归一 (0<= x ,y <= 10)
输出描述:
每行输出通过万生药水和万物归一的变换之后,最后的神秘法宝的容积。同时容积对mod取余。
178 之后的阶层取余modmod 就是为0 了。所以我们只需要暴力计算前178 项即可。
//求组合数:
c[0][0]=1;
for (int i=1; i<=3000; ++i)
{
c[i][0]=1;
for (int j=1; j<=3000; ++j)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
typedef long long ll;
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
ll c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
ll mod=3777105087;
ll f[180],s[180];
int main(void)
{
f[1]=1;
for(int i=2;i<=178;i++){
f[i]=f[i-1]*i%mod;
s[i]=(s[i-1]+f[i])%mod;//从2开始加的累加2!+3!+4!+...
}
ll n;
while(cin>>n){
int x,y;
cin>>x>>y;
int ans=1;
if(y) for(int i=1;i<=x;i++) ans*=2;
if(n>178) cout<<s[178]*ans%mod+1<<endl;
else cout<<s[n]*ans%mod+1<<endl;
}
return 0;
}
G 芒砀山的神秘数字
题目描述
巫山老伯所在地芒砀山有神秘数字的出现,世人惊讶。此神秘数字一旦破解,秦皇便可以此长生不老,构建万世天宫。
神秘数字是在一个陨石坠落之时,所产生的。陨石坠落时分为两块,分别落在了芒砀山的南北两侧。导致芒砀山南北两侧皆有一串神秘数字。
现秦始皇派巫山老伯前去解开此神秘数字背后的秘密。
神秘数字南北方的长度分别为n和m。
巫山老伯发现,此两串神秘数字的背后隐藏的秘密是一个数。
巫山老伯发现神秘数字背后的数字就是南方神秘数字串的子序列的值大于北方神秘数字串的值的序列个数。
输入描述:
输入T (T<= 10)
输入n m 表示南方神秘数字串的长度和北方神秘数字串的长度。(1<= m <= n <= 3000 )
输入南方神秘数字串
输入北方神秘数字串
输出描述:
输出两串神秘数字的背后隐藏的秘密是一个数,并将此数对998244353取模。
想了很久还是难以看出那个点,dp还是很难理解。
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
typedef long long ll;
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
ll c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
ll mod=998244353;
ll c[3005][3005];
ll dp[3005][3005];
void pre()
{
c[0][0]=1;
for(int i=1;i<=3000;i++){
c[i][0]=c[i][i]=1;
for(int j=1;j<=3000;j++){
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
}
int main(void)
{
pre();
int t;cin>>t;
int n,m;
string sn,sm;
while(t--){
cin>>n>>m>>sn>>sm;
sn=" "+sn;
sm=" "+sm;
ll ans=0;
//计算n的长度大于m的长度的时候
for(int i=1;i<=n;i++){
if(sn[i]=='0') continue;
for(int j=m;j<=n-i;j++){
ans=(ans+c[n-i][j])%mod;//在sn的i后面取出j个来排序
}
}
//计算长度相等的时候
dp[0][0]=1;
for(int i=1;i<=n;i++){
dp[i][0]=1;
for(int j=1;j<=m;j++){//对于每一个sn的i开始的,遍历sm串
//动态过程
dp[i][j]=dp[i-1][j];
if(sn[i]==sm[j]){
dp[i][j]+=dp[i-1][j-1];
}
dp[i][j]%=mod;
//记录答案
if(sn[i]>sm[j]){
ans=(ans+dp[i-1][j-1]*c[n-i][m-j]%mod)%mod;
}
}
}
cout<<ans<<endl;
}
return 0;
}
H 小李堆积木
题目描述
有一天小李爸爸老李送了个积木给小李玩,积木里面就分两种,黑白方块,老李给了小李一个任务,这里给出图形堆的规则
第一阶段
1
第二阶段
1 1
0 1
第三阶段
1 1 1 1
0 1 0 1
0 0 1 1
1 0 0 1
. . .等
规则是:
分为四个部分
1 | 1
——
0 | 1
左1 右1 右2 都是和 n-1阶段相同
左2 和 n-1阶段相反
然后老李想要知道第n阶段是什么
输入描述:
第一行 输入一个t,代表数据组数(1<=t<=10)
第二行 输入一个n,代表要求第n阶段是什么(1<=n<=10)
输出描述:
下面t组数据,分别输出第n阶段的积木堆的情况
每次从第一阶段推到第n 阶段即可
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
typedef long long ll;
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
ll c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
int a[700][700];
void pre()
{
for(int i=0;i<=8;i++){
int k=pow(2,i);
for(int ii=1;ii<=k;ii++){
for(int jj=1;jj<=k;jj++){
a[ii][jj+k]=a[ii+k][jj+k]=a[ii][jj];
if(!a[ii][jj]) a[ii+k][jj]=1;
}
}
}
}
int main(void)
{
a[1][1]=1;
pre();
int t;cin>>t;
while(t--){
int n;cin>>n;
n=pow(2,n-1);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
}
return 0;
}
J 小阳排队
题目描述
小阳想要买个东西,然后就去了商店,发现进商店需要排队(生意太火爆!),然后就开始漫长的等待,他觉得自己
太无聊,便开始思考一个问题,这个队伍的人每个人可以做两种操作,插到队头或者队尾,然后问你最小的操作次数
使队伍有序
输入描述:
第一行 输入一个t,代表数据组数(1<=t<=10)
第二行 输入一个n,代表n个人在这里排队(1<=n<=500000)
第三行 这一行n个数,是n个数的排列,代表每个人的身高
输出描述:
有t行,每行一个数,代表最小的操作次数使它有序
求一个最长连续的子序列
转移方程 dp[i]=max(dp[i],dp[i−1]+1) ;
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
typedef long long ll;
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
ll c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
int f[500005];
int a[500005];
int main(void)
{
int t;t=read();
while(t--){
memset(f,0,sizeof f);
int n;n=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
int ans=0;
for(int i=1;i<=n;i++){
f[a[i]]=f[a[i]-1]+1;
ans=max(ans,f[a[i]]);
}
cout<<n-ans<<endl;
}
return 0;
}
K 小阳数数
题目描述
武林内纷乱不断,各地都自立门派,门派的人为了识别门内弟子,给了每个人一块令牌,这个令牌有个神奇的地方,
门派内的弟子的令牌不一定相同,
下面是他的识别规则:
每个人的令牌都是一串数字,如果两个人的令牌有相似的地方,即有相同的数字,那就属于同一个门派,特别的,
如果两个人没有相同的数字,但是这个两个人都和另一个人有相同的数字,那么这三个人同属一个门派,现在有一个任务
,给你n个令牌,让你认出有多少个门派
例如
3
13579
2468
12
这里答案应该是1,因为第一个人和第二个人同时和第三个人有关系
输入描述:
第一行 输入一个t,代表数据组数(1<=t<=10)
第二行 输入一个n,代表n块令牌 (1<=n<=1000)
下面n行,每行一个数字序列,(1<=len<=1000)
输出描述:
有t行,每行一个数,代表有这组数据有多少个门派
并查集;数据很小,也可以暴力解决
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
#define ll long long
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
int read()
{
int c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
int a[15];
int b[10];
int find1(int k)//找爸爸
{
if(a[k]==k) return k;
else return a[k]=find1(a[k]);
}
int main(void)
{
int t;t=read();
while(t--){
for(int i=0;i<=9;i++) a[i]=i,b[i]=0;//初始化爸爸
int n;n=read();
string s;
for(int j=1;j<=n;j++){
cin>>s;
int temp=find1(s[0]-'0');//拿出第一个数的爸爸
b[s[0]-'0']=1;//标记这个数有了
for(int i=1;i<s.length();i++){
int k=find1(s[i]-'0');//下一个数字的爸爸
if(temp!=k){//爸爸不一样
a[k]=temp;//认temp为爸爸
}
b[s[i]-'0']=1;
}
}
int num=0;
for(int i=0;i<=9;i++){
if(i==find1(i)&&b[i]==1){//如果这个数字出现过并且自己认自己做爸爸
num++;
}
}
cout<<num<<endl;
}
return 0;
}
M 来来来 比比咱谁更聪明
题目描述
小j和小k一起玩一个简单的小游戏,有一个容量为n的瓶子,此外还有m个容量不等杯子,他们用杯子装满水轮流往瓶子中倒水,如果谁把杯子中的水不能完全倒入瓶子中,则算输,小j先开始往瓶中倒水,两个人都足够聪明,请问,小j能赢吗?
注意: 每一个杯子可以重复用多次
输入描述:
输入要求:首先输入n表示瓶子的容量,接下来输入m表示杯子的数量,
接下来输入m个数表示杯子的容量k(0
输出要求:如果能赢则输出Y,否则输出N。
n,m较小,故可以模拟整个过程,当n能恰好被填满或不能再装时赢,否则输
#include
#define MAX_INT ((unsigned)(-1)>>1)
#define MIN_INT (~MAX_INT)
#define pi 3.1415926535898
typedef long long ll;
#define inf 0x3f3f3f3f
#define infmax 0x3f3f3f3f3f3f3f3f
using namespace std;
ll read()
{
ll c=0;int flag=1;
char s;
while((s=getchar())>'9'||s<'0')if(s=='-')flag=-1;
c=s-'0';
while((s=getchar())<='9'&&s>='0') c=c*10+s-'0';
return c*flag;
}
int f[1005];
int a[1005];
int main(void)
{
int n,m;cin>>n>>m;
for(int i=1;i<=m;i++) cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i>=a[j]&&f[i-a[j]]==0)//这个j的杯子可以倒水且倒完后可以再一次倒完
f[i]=1;
}
}
if(f[n]) cout<<"Y";
else cout<<"N";
return 0;
}