原题链接:https://vjudge.net/contest/340569#problem/A
题意: 收到礼物,然后重新放到不同的位置上,问方案有多少个?
思路: 错排模板题,直接套用错排公式并取模即可。
注意要用long long 型,否则WA!
不懂错排公式怎么来的看这里:彻底搞懂错排公式
Code(C++):
#include
#include
using namespace std;
typedef long long ll;
ll dp[105];
const int N=1e9+7;
int main(){
int t; scanf("%d",&t);
dp[1]=0;
dp[2]=1;
for(int i=3;i<=100;i++)
dp[i]=(i-1)*(dp[i-1]+dp[i-2])%N;
while(t--){
int n;
scanf("%d",&n);
printf("%lld\n",dp[n]);
}
}
原题链接:https://vjudge.net/contest/340569#problem/C
题意: 男生魅力值用负整数表示,女生魅力值用正整数表示,如果某位置的邻居和该位置主人性别不同,则总分加上邻居魅力值的绝对值,否则减去。注意这里的魅力总分不包含该位置上的魅力值。
思路: 所有位置的魅力值存入数组 a[ ][ ],数组b[ ][ ]用来存每个位置周围的魅力值总和。然后遍历每个位置,算出该位置周围的魅力值总和,性别相同的,减掉魅力值绝对值,否则加上魅力值绝对值。最后再遍历所有位置,不断更新最大魅力值所在的位置以及总和。
Code(C++):
#include
#include
using namespace std;
int a[25][25],b[25][25];
int main(){
int n,m;
while(cin>>n>>m){
if(n==0 && m==0)
break;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
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++){
b[i][j]=0;
if(a[i][j]>0){
if(a[i-1][j]!=0)
b[i][j]-=a[i-1][j];
if(a[i+1][j]!=0)
b[i][j]-=a[i+1][j];
if(a[i][j-1]!=0)
b[i][j]-=a[i][j-1];
if(a[i][j+1]!=0)
b[i][j]-=a[i][j+1];
}
else if(a[i][j]<0){
if(a[i-1][j]!=0)
b[i][j]+=a[i-1][j];
if(a[i+1][j]!=0)
b[i][j]+=a[i+1][j];
if(a[i][j-1]!=0)
b[i][j]+=a[i][j-1];
if(a[i][j+1]!=0)
b[i][j]+=a[i][j+1];
}
}
}
int x=1,y=1,ans=b[1][1];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(b[i][j]>ans){
ans=b[i][j];
x=i,y=j;
}
}
}
cout<<x<<" "<<y<<" "<<ans<<endl;
}
}
原题链接:https://vjudge.net/contest/340569#problem/D
题意: 给你n个数a[1]、a[2]… a[n]和m个询问。每一个询问输入l,r,d,询问在区间l和r中,是否满足a[l] * a[l+1] * … * a[r] 能被d整除。
思路: 集训的时候知道直接遍历会TLE,但没什么新的思路,就试了一下Java大整数类暴力遍历,果然,TLE了。对于 k 是不是 d 的倍数,我们可以对这两个数分解质因数,如果满足对于 d 的每一个质因数,在 k 中都有出现过,且在 k 中出现的次数大于等于d的出现次数,则 k 是 d 的倍数。
Code(C++):
#include
#include
#include
#include
using namespace std;
const int N=1e5+100;
vector<int> v[N];
int main(){
int t; scanf("%d",&t);
while(t--){
for(int i=1;i<N;i++) //记得初始化vector
v[i].clear();
int n,m;
scanf("%d%d",&n,&m);
int x;
for(int i=1;i<=n;i++){
scanf("%d",&x);
for(int j=2;j*j<=x;j++){
while(!(x%j)){
v[j].push_back(i); //该数可分解几次,就存入该数下标几次,注意这里存入的是对应质因数的动态数组
x/=j;
}
}
if(x>1) v[x].push_back(i); //如果该数还没除完,还是个质数,需要再存入一次
}
while(m--){
int l,r,d;
scanf("%d%d%d",&l,&r,&d);
int vis=0;
for(int i=2;i*i<=d;i++){ //分解d的质因数
int sum1=0;
while(!(d%i)){
sum1++; //记录每个质因数的个数
d/=i;
}
if(sum1){
int sum2=upper_bound(v[i].begin(),v[i].end(),r)-lower_bound(v[i].begin(),v[i].end(),l); //计算每个质因数的总数
if(sum2<sum1){ //如果d中的质因数大于k中的,则不符合
vis=1;
break;
}
}
}
if(d>1){ //同理,整除后d还是质数的情况
int sum2=upper_bound(v[d].begin(),v[d].end(),r)-lower_bound(v[d].begin(),v[d].end(),l);
if(!sum2) vis=1;
}
if(vis)
printf("No\n");
else
printf("Yes\n");
}
}
return 0;
}
原题链接:https://vjudge.net/contest/340569#problem/E
题意: 给定一个字符串,在有限查询次数内输出所要查询区间的字典序最小的子串个数。
思路: 查找给定区间中字典序最小的字母出现的次数。
注意:好像用cin、cout会TLE。
Code(C++):
#include
#include
#include
using namespace std;
const int N=1e5+10;
char s[N];
int a[N][30]; //一维表示下标,二维表示字母
int main(){
int t; scanf("%d",&t);
for(int k=1;k<=t;k++){
memset(a,0,sizeof(a)); //记得每次输入前初始化
int n,m;
scanf("%d%d",&n,&m);
scanf("%s",s+1); //下标右移一位
printf("Case #%d:\n",k);
for(int i=1;i<=n;i++){
a[i][s[i]-'A']++; //记录每个位置字母出现的次数
for(int j=0;j<26;j++) //遍历字母表
a[i+1][j]=a[i][j]; //累加每个字母在前面出现的次数
}
while(m--){
int l,r;
scanf("%d%d",&l,&r);
for(int j=0;j<26;j++){
//如果该区间的前一个区间该字母出现次数与该区间相等,说明该区间没出现该字母
if(a[l-1][j]!=a[r][j]){ //不相等说明出现,一经出现说明字典序最小,跳出循环
printf("%d\n",a[r][j]-a[l-1][j]);
break;
}
}
}
}
return 0;
}
原题链接: https://vjudge.net/contest/340569#problem/F
题意: 输出验题人中的最小代码字节数和AC队伍中选手最小的代码字节数,若不存在则输出N/A。
思路: 直接模拟即可。
Code(C++):
#include
#include
#include
using namespace std;
int a[100],b[505];
int main(){
int t; cin>>t;
for(int k=1;k<=t;k++){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
int n,m;
cin>>n>>m;
int minn1=70000;
for(int i=1;i<=n;i++){
cin>>a[i];
minn1=min(minn1,a[i]);
}
int minn2=70000;
for(int i=1;i<=m;i++){
cin>>b[i];
minn2=min(minn2,b[i]);
}
cout<<"Problem "<<1000+k<<":"<<endl;
cout<<"Shortest judge solution: "<<minn1<<" bytes."<<endl;
if(m!=0)
cout<<"Shortest team solution: "<<minn2<<" bytes."<<endl;
else
cout<<"Shortest team solution: N/A bytes."<<endl;
}
}
原题链接: https://vjudge.net/contest/340569#problem/G
题意: 额,直接看原题吧,太长了,中文题目不难理解。
思路: 模拟题,直接看代码吧,不难懂!注意左以及右对齐的写法。
Code(C++):
#include
#include
using namespace std;
int main(){
int t; cin>>t;
for(int k=1;k<=t;k++){
int rank; cin>>rank;
string str;
cin>>str;
int prob; cin>>prob;
string T;
cin>>T;
int x;
if(T=="Running")
cin>>x;
cout<<setw(3)<<setfill(' ')<<right<<rank<<"|";
cout<<setw(16)<<setfill(' ')<<left<<str<<"|"<<prob<<"|";
if(T=="Running"){
cout<<"[";
for(int i=1;i<=x;i++)
cout<<"X";
for(int i=1;i<=10-x;i++)
cout<<" ";
cout<<"]"<<endl;
}
else{
cout<<"[";
if(T=="FB"){
cout<<" "<<"AC*";
int len=T.length();
for(int i=1;i<=5-len;i++)
cout<<" ";
cout<<"]"<<endl;
}
else{
cout<<" "<<T;
int len=T.length();
for(int i=1;i<=6-len;i++)
cout<<" ";
cout<<"]"<<endl;
}
}
}
return 0;
}
原题链接: https://vjudge.net/contest/340569#problem/H
题意: 电梯每向上运行一层需要6秒钟,向下运行一层需要4秒钟,每开门一次需要5秒(如果有人到达才开门),并且每下一个人需要加1秒。 电梯最开始在0层,并且最后必须再回到0层才算一趟任务结束。求电梯跑一趟所需时间。
思路: 先把所有要去的楼层从小到大排序,对每个数,与前一个数相比,如果相等,说明这两个人都在该层下,则不需要再算开门时间,否则要算上开门时间。
Code(C++):
#include
#include
#include
using namespace std;
int a[105];
int main(){
int t; cin>>t;
while(t--){
memset(a,0,sizeof(a));
int n; cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
int ans=0;
for(int i=1;i<=n;i++){
if(a[i]-a[i-1]!=0)
ans=ans+(a[i]-a[i-1])*6+1+5;
else
ans=ans+(a[i]-a[i-1])*6+1;
}
ans=ans+a[n]*4;
cout<<ans<<endl;
}
return 0;
}