传送门:https://www.jisuanke.com/contest/1558?view=challenges
A. Magic Mirror
签到模拟(通过率: 98.74 %,通过人数: 1650)
思路:把输入的字符串转成小写串,然后和”jessie”进行比较,如果相等就输出”Good guy!”,不然就输出另一个
// https://nanti.jisuanke.com/t/31710
#include<stdio.h>
#include<string.h>
char str[]="jessie";
char s[30];
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
int t;scanf("%d",&t);
while(t--){
scanf("%s",s);
for(char*p=s;*p;p++)
*p|=32;
if(strcmp(s,str)==0)
puts("Good guy!");
else
puts("Dare you say that again?");
}
return 0;
}
~ B. Mathematical Curse
dp(通过率: 73.49 %,通过人数: 585)
思路:dp[i][j]代表用了前i个数字和前j个运算符所能达到的极值,+-只能从最大值转移到最大值,最小值转移到最小值,但是*/有可能有数是负数,所以要考虑最大值/最小值之间的相互转移.最后输出dp[n][m]的最大值.
#include<stdio.h>
#include<string.h>
typedef long long ll;
const int maxn=1005,MAX=1,MIN=0;
ll max[maxn][6],min[maxn][6];
char s[7];int a[maxn];
void sel(int mode,ll&a,ll b){
if(mode&&b>a)a=b;
if(!mode&&b<a)a=b;
}
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
int t;scanf("%d",&t);
while(t--){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
scanf("%s",s+1);
for(int i=0;i<maxn;i++)
for(int j=0;j<6;j++)
max[i][j]=-0x3f3f3f3f3f3f3f3f,
min[i][j]=0x3f3f3f3f3f3f3f3f;
max[0][0]=min[0][0]=k;
for(int i=1;i<=n;i++){
max[i][0]=min[i][0]=max[i-1][0];
for(int j=1;j<=m&&j<=i;j++){
switch(s[j]){
case '+':
sel(MAX,max[i][j],max[i-1][j]);
sel(MAX,max[i][j],max[i-1][j-1]+a[i]);
sel(MIN,min[i][j],min[i-1][j]);
sel(MIN,min[i][j],min[i-1][j-1]+a[i]);
break;
case '-':
sel(MAX,max[i][j],max[i-1][j]);
sel(MAX,max[i][j],max[i-1][j-1]-a[i]);
sel(MIN,min[i][j],min[i-1][j]);
sel(MIN,min[i][j],min[i-1][j-1]-a[i]);
break;
case '*':
sel(MAX,max[i][j],max[i-1][j]);
sel(MAX,max[i][j],max[i-1][j-1]*a[i]);
sel(MAX,max[i][j],min[i-1][j-1]*a[i]);
sel(MIN,min[i][j],min[i-1][j]);
sel(MIN,min[i][j],min[i-1][j-1]*a[i]);
sel(MIN,min[i][j],max[i-1][j-1]*a[i]);
break;
case '/':
sel(MAX,max[i][j],max[i-1][j]);
sel(MAX,max[i][j],max[i-1][j-1]/a[i]);
sel(MAX,max[i][j],min[i-1][j-1]/a[i]);
sel(MIN,min[i][j],min[i-1][j]);
sel(MIN,min[i][j],min[i-1][j-1]/a[i]);
sel(MIN,min[i][j],max[i-1][j-1]/a[i]);
break;
}
}
}
printf("%lld\n",max[n][m]);
}
return 0;
}
G. Give Candies
数论(通过率: 80.62 %,通过人数: 1202)
思路:首先需要求出来有N颗糖的发糖方案,是2^N(随便列几项找到的规律)
其次需要求出2^N%(1e9+7),利用费马小定理,直接将N%(1e+6)之后快速幂即可
// https://nanti.jisuanke.com/t/31716
#include<stdio.h>
typedef long long ll;
const int mod=1e9+7;
ll pow(ll x,ll y){
ll ret=1;y%=mod;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y/=2;
}
return ret;
}
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
int t;scanf("%d%*c",&t);
while(t--){
ll y=0;char c;
while((c=getchar())!='\n'&&c!=EOF)
y=(y*10+c-'0')%(mod-1);
printf("%lld\n",pow(2,y-1+mod));
}
return 0;
}
I. Save the Room
签到模拟(通过率: 98.37 %,通过人数: 1631)
思路:只要有一个偶数,2就可以在那个方向上填充满,所以当全是奇数的时候就不能全部填充满了
// https://nanti.jisuanke.com/t/31718
#include<stdio.h>
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
int a,b,c;
while(~scanf("%d%d%d",&a,&b,&c))
puts((a%2)*(b%2)*(c%2)?"No":"Yes");
return 0;
}
~ J. Participate in E-sports
大数求根(通过率: 51.65 %,通过人数: 298)
思路:只要判断n和n*(n-1)/2是不是完全平方数就可以了,主要是怎么开根的问题
// https://nanti.jisuanke.com/t/31719
import java.math.BigInteger;
public class Main{
public static BigInteger bigSqrt(String s){
BigInteger remain=BigInteger.ZERO;
BigInteger odd=BigInteger.ZERO;
BigInteger ans=BigInteger.ZERO;
int group=0,k=0;
if(s.length()%2==1){
group=s.charAt(0)-'0';
k--;
}
else{
group=(s.charAt(0)-'0')*10+s.charAt(1)-'0';
}
for(int j=0;j<(s.length()+1)/2;j++){
if(j!=0)
group=(s.charAt(j*2+k)-'0')*10+s.charAt(j*2+k+1)-'0';
odd=BigInteger.valueOf(20).multiply(ans).add(BigInteger.ONE);
remain=BigInteger.valueOf(100).multiply(remain).add(BigInteger.valueOf(group));
int count=0;
while(remain.compareTo(odd)>=0){
count++;
remain=remain.subtract(odd);
odd=odd.add(BigInteger.valueOf(2));
}
ans=ans.multiply(BigInteger.TEN).add(BigInteger.valueOf(count));
}
return ans;
/*
remind=0;
odd=0;
ans=0;
group=0;
k=0;
if(s.length()%2==1)
group=s[0]-'0',k--;
else
group=s[0]*10+s[1]-'0'*11;
for(int j=0;j<(s.length()+1)/2;j++){
if(j)
group=s[j*2+k]*10+s[j*2+k+1]-'0'*11;
odd=20*ans+1;
remind=100*remind+group;
int count=0;
while(remain>=odd){
count++;
remain-=odd;
odd+=2;
}
ans=ans*10+count;
}
return ans;
*/
}
public static void main(String[] args){
try{
java.io.FileInputStream fis=new java.io.FileInputStream("E:/ACM/SRC/1.txt");
System.setIn(fis);
}catch(Exception e){}
try{
java.io.FileInputStream fis=new java.io.FileInputStream("E:/ACM/SRC/1.txt");
System.setIn(fis);
}catch(Exception e){}
java.util.Scanner cin=new java.util.Scanner(System.in);
int t=cin.nextInt();
for(int i=0;i<t;i++){
BigInteger num=cin.nextBigInteger();
BigInteger ans=num.multiply(num.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2));
String sans=ans.toString();
String snum=num.toString();
BigInteger a1=bigSqrt(snum);
BigInteger a2=bigSqrt(sans);
int t1=a1.multiply(a1).compareTo(num)==0?2:0;
int t2=a2.multiply(a2).compareTo(ans)==0?1:0;
/*
cin>>num;
ans=num*(num-1)/2;
a1=sqrt(num);
a2=sqrt(ans);
t1=(a1*a1==num)*2;
t2=(a2*a2==num)*1;
*/
String[] ans_str={"League of Legends","Clash Royale","Hearth Stone","Arena of Valor"};
System.out.println(ans_str[t1+t2]);
}
cin.close();
}
}
~ K. Transport Ship (差一点就做出来了TAT)
背包dp(通过率: 79.48 %,通过人数: 674)
思路:问你特定花费下多重背包方案数
首先二进制拆分物品数目变成01背包方案数
求方案数就是把max改成sum,然后dp[0]=1
// https://nanti.jisuanke.com/t/31720
#include<stdio.h>
#include<string.h>
#include<algorithm>
typedef long long ll;
const int mod=1e9+7;
ll dp[10005];
int cost[405];
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
int t;scanf("%d",&t);
while(t--){
int n,q,v,c;scanf("%d%d",&n,&q);
int cnt=1;
for(int i=1;i<=n;i++){
scanf("%d%d",&v,&c);
for(int i=0;i<c;i++)
cost[cnt++]=v,v+=v;
}
memset(dp,0,sizeof dp);dp[0]=1;
for(int i=1;i<cnt;i++)
for(int j=10000;j>=cost[i];j--)
dp[j]=(dp[j]+dp[j-cost[i]])%mod;
while(q--){
scanf("%d",&c);
printf("%lld\n",dp[c]);
}
}
return 0;
}
L. Poor God Water
dp+矩阵快速幂(通过率: 88.97 %,通过人数: 750)
思路:dp[i][j][k][l]代表着已经考虑了前i个,结尾三个是jkl的方案数(实际长度是i+3)
假如说肉:1鱼:2巧克力:3
那么有如下转移
dp[i][1][2][3]=dp[i-1][1][1][2]+dp[i-1][2][1][2]+dp[i-1][3][1][2]
也就是dp[i][j][k][?]可以由dp[i-1][?][j][k]转移而来
但是有7个不合法的情况:111,222,333,132,231,313,323
所以最后就是20个状态有一个转移系数矩阵,用矩阵快速幂来求得答案
小技巧:因为会多次调用系数矩阵的2的幂次,所以可以提前处理出来系数矩阵的幂次
然后要求什么N次幂,就二进制分解把该乘的都乘起来就好了.
// https://nanti.jisuanke.com/t/31721
#include<stdio.h>
#include<string.h>
#include<map>
#define mod 1000000007
typedef long long ll;
const ll def[]={
0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,
1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,
1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,
0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,
0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,
0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,
0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0
};
struct matrix{
ll a[20][20];
matrix(){
memset(a,0,sizeof(a));
}
matrix(int x){
memset(a,0,sizeof(a));
for(int i=0;i<20;i++)
a[i][i]=1;
}
matrix(const matrix©){
memcpy(a,copy.a,sizeof(a));
}
void special(){
memcpy(a,def,sizeof a);
}
ll sum(){
ll ret=0;
for(int i=0;i<20;i++)
for(int j=0;j<20;j++)
ret+=a[i][j];
return ret%mod;
}
matrix operator+(const matrix&other){
matrix ret;
for(int i=0;i<20;i++)
for(int j=0;j<20;j++)
for(int k=0;k<20;k++)
ret.a[i][j]=(ret.a[i][j]+a[i][j]+other.a[i][j])%mod;
return ret;
}
matrix operator*(const matrix&other){
matrix ret;
int i,j,k;
for(i=0;i<20;i++)
for(j=0;j<20;j++)
for(k=0;k<20;k++)
ret.a[i][j]+=a[i][k]*other.a[k][j],
ret.a[i][j]%=mod;
return ret;
}
matrix&operator*=(const matrix&other){*this=*this*other;
return*this;
}
matrix operator^(ll index){
matrix ret(1);
matrix base(*this);
while(index){
if(index&1)
ret*=base;
base*=base;
index>>=1;
}
return ret;
}
}m,two[34];
std::map<ll,ll>map;
ll pow(ll y){
if(map.count(y))return map[y];
matrix ret(1);
for(int i=0;i<34;i++)
if(y&(1LL<<i))
ret*=two[i];
return map[y]=ret.sum();
}
int main(){
#ifdef LOCAL_DEBUG
freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
m.special();
two[0]=m;
for(int i=1;i<34;i++)
two[i]=two[i-1]*two[i-1];
int t;scanf("%d",&t);
while(t--){
ll x;scanf("%lld",&x);
if(x<=3)
switch(x){
case 1:puts("3");break;
case 2:puts("9");break;
case 3:puts("20");break;
}
else
printf("%lld\n",pow(x-3));
}
return 0;
}
发现自己真是太菜了,打~是赛后补的题.