1. 程式人生 > 實用技巧 >2020YPACM社團年終賽(暨實驗室選拔賽)

2020YPACM社團年終賽(暨實驗室選拔賽)

20級學弟學妹們記得補題嗷

A 小Q要簽到!

題面

給n個a,b,c的整數(範圍都在[1,1000]),問有沒有兩個整數x,y,使得a * x+b * y=c

如果有輸出yes,沒有輸出no

思路

思路一:因為時限給了3000ms,所以可以暴力找x和y從-1000到1000的4e6種情況

思路二:也可以用gcd做,c%gcd(a,b)=0就是yes,其餘都是no

ac程式碼

思路一

#include<bits/stdc++.h>
using namespace std;
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,p,q;
        scanf("%d%d%d",&n,&p,&q);
        int flag=0;
        for(int i=-1000;i<=1000;i++){
            for(int j=-1000;j<=1000;j++){
                if(i*n+j*p==q){
                    printf("yes\n");flag=1;break;
                }
            }
            if(flag){break;}
        }
        if(!flag){
            printf("no\n");
        }
    }
    return 0;
}

思路二

#include<bits/stdc++.h>
using namespace std;
int main(){
	int t,a,b,c;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&a,&b,&c);
		if(c%__gcd(a,b)==0) printf("yes\n");
        else printf("no\n");
	}
	return 0;
}

B 你不要過來啊!

題面

給二維座標點(x,y),給n個字串,WASD代表上左下右,問每次從(0,0)開始走能到(x,y)嗎,走到YES,沒走不到NO

思路

簽到,按照字串模擬

ac程式碼

#include<bits/stdc++.h>
using namespace std;
char s[110];
int main(){
    int t;
    scanf("%d",&t);
    int x,y;
    scanf("%d%d",&x,&y);
    while(t--){
        scanf("%s",s);
        int l=strlen(s);
        int x1=0,y1=0;
        for(int i=0;i<l;i++){
            if(s[i]=='W') y1++;
            else if(s[i]=='A') x1--;
            else if(s[i]=='S') y1--;
            else if(s[i]=='D') x1++;
        }
        if(x==x1 && y1==y) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

C 十里坡劍神(二)

題面

輸入有n個亡靈逆轉和m個血脈驟殺

血脈驟殺能殺死一個丘丘人(效果等效於死亡數 +1),亡靈逆轉能使得每個已經死去的丘丘人在一瞬間會同步殺死一個丘丘人(效果等效於死亡數 * 2)

能殺多少丘丘人?(因為數量可能過大,需要取餘,模數為998244353)

思路

很明顯2^n * m,但因為資料2e7,所以我們這裡引進一個簡單的演算法,快速冪(不懂的學弟可自行百度或者問學長)

ac程式碼

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int pow_mod(ll a, ll n){
    ll m=998244353;
    long long ans = 1;
    while(n){
        if(n&1){
            ans = (ans * a) % m;
        }
        a = (a * a) % m;
        n >>= 1;
    }
    return ans;
}
int main(){
    int n,m;
    ll sum;
    while(~scanf("%d%d",&n,&m)){
        int mod=998244353;
        sum=m;
        sum=sum*pow_mod(2,n)%mod;
        printf("%lld\n",sum);
    }
    return 0;
}

D 十里坡劍神(三)

題面

輸入n個長度為l(l<=50)的兩個整數,大數相加

思路

模擬即可

ac程式碼

#include<bits/stdc++.h>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
char s[55],ss[55];
int k[55];
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n;scanf("%d",&n);
        scanf("%s%s",&s,&ss);
        int c=0;
        for(int i=n-1;i>=0;i--){
            k[i]=c+s[i]+ss[i]-'0'-'0';
            c=k[i]/10;k[i]%=10;
        }
        if(c){
            printf("%d",c);
           for(int i=0;i<n;i++)printf("%d",k[i]);
        }
        else{
            for(int i=0;i<n;i++)printf("%d",k[i]);
        }
        printf("\n");
    }
    return 0;
}

E 小小攀登者

題面

給n和m兩個整數,再給長度為n的陣列,可以從數值低到數值高,但從數值高到數值低的差需要小於等於m,如果大於就要把數值高的值減到兩者差小於等於m

問最小減去多少單位

思路

因為正著遍歷不利於判斷,如果需要減少數值,會對前面判斷過的數值造成影響,所以我們倒著遍歷即可

看好多學弟卡了,這裡解釋下一組資料,為什麼要倒著

3 0

5 5 3

因為5->3,不能走,所以要削成3,但如果你不削第一個5的話,當你第一個五走到被削成的3的時候又不能走,所以這題要預判,把第一個五也削成3

ac程式碼

#include<bits/stdc++.h>
using namespace std;
int h[100010];
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++){
            scanf("%d",&h[i]);
        }
        int sum=0;
        for(int i=n-1;i>=1;i--){
            if(h[i]-h[i+1]>m){
                sum+=(h[i]-(h[i+1]+m));
                h[i]=h[i+1]+m;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

F 賽博朋克2020

題面

求1582年10月15號之後的年份到2077還要多少天

思路

當輸入2077年份的時候,day永遠是0天

判斷閏年和注意輸出的格式即可

ac程式碼

#include<bits/stdc++.h>
#define ll long long
#define mod 10
using namespace std;
int day[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int pan(int year){
    return (year%4==0 &&year%100!=0)||(year%400==0);
}
int main(){
    int y,m,d;
    while(~scanf("%d-%d-%d",&y,&m,&d)){
         if(y==0 && m==0 && d==0){return 0;}
         if(y==2077){printf("0 day to 2077\n");continue;}
         int ans=0;
         ans=day[m-1]-d+1;
         if(pan(y) && m<=2){
            ans++;
         }
         for(int i=m;i<12;i++){
            ans+=day[i];
         }
         for(int i=y+1;i<2077;i++){
            if(pan(i)) ans+=366;
            else ans+=365;
         }
         if(ans==1)printf("1 day to 2077\n");
         else printf("%d days to 2077\n",ans);
    }
    return 0;
}

G 貓和老鼠

題面

老鼠們排成一隊,每個老鼠都按位置有自己的編號,Tom會放過一隻老鼠,Tom按照天數來判斷是吃奇數位置上還是偶數位置上的老鼠。

最後活下來的一隻老鼠就被放生了。Jerry要知道自己站幾號才能活.

思路

思路一:因為每次去掉一半,所以是log2級別的,模擬即可

思路二:找規律,會發現1個1號 4個2號 16個6號 64個22號

於是發現了1到1是0+1=1,2到5是1+1=2,6到21是1+4+1=6,22到85是1+4+16+1=22

就是4^n的字首和

ac程式碼

思路一

#include<bits/stdc++.h>
using namespace std;
int p[2][1000010];
int main(){
    int n;
    while(~scanf("%d",&n)){
        int k=n,c=1;
        for(int i=1;i<=n;i++){
            p[0][i]=i;
        }
        while(k!=1){
            int cnt=0,j=c%2;
            for(int i=c%2+1;i<=k;i+=2){
                p[j][++cnt]=p[1-j][i];
            }
            k=cnt;c++;
        }
        c++;
        printf("%d\n",p[c%2][1]);
    }
    return 0;
}

思路二

#include<bits/stdc++.h>
using namespace std;
int p[15];
int a[15];
int main(){
    int n;
    p[1]=1;
    for(int i=2;i<15;i++){
        p[i]=p[i-1]*4;
    }
    a[0]=0;a[1]=p[1];
    for(int i=2;i<15;i++){
        a[i]=a[i-1]+p[i];
    }
    while(~scanf("%d",&n)){
        int pos=0;
        for(int i=1;i<15;i++){
            if(n>a[i]){
                pos=a[i];
            }
        }
        printf("%d\n",pos+1);
    }
    return 0;
}

H 蕭山楊少

題面

輸出n^m的個位數字乘上1e5

思路

思路一:快速冪,mod為10

思路二:用提示做,對於任意一個整數X,X^5的個位數等於其X的個位數,m%5

ac程式碼

思路一

#include<bits/stdc++.h>
#define ll long long
#define mod 10
using namespace std;
ll n,m;
ll ans;
ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1){
            ans*=a;ans%=mod;
        }
        a*=a;a%=mod;
        b>>=1;
    }
    return ans;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        printf("%lld\n",ksm(n,m)*100000);
    }
    return 0;
}

思路二

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,m,t;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		m=(m-1)%4;
		n%=10;
		if(m==0)
			printf("%d\n",n*100000);
		else	
			printf("%d\n",(int)(pow(n,m+1))%10*100000);
	}
	return 0;
} 

I 八奇的金子

題面

求1~n的因子個數之和

思路

不好意識上面那個圖算的是g(n)不是g(x),懶狗不想再搞一遍了

ac程式碼

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
    ll n;
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        ll k=(ll)sqrt(n);
        ll sum=0;
        for(ll i=1;i<=k;i++){
            sum+=(ll)(n/i);
        }
        sum*=2;sum-=k*k;
        cout<<sum<<endl;
    }
    return 0;
}

J ouluy愛畫畫

思路

簽到題

ac程式碼

#include<stdio.h>
int main(){
    int n,m;
    scanf("%d%d",&n,&m);int h=m-n;
    for(int i=0;i<=h;i++){
       for(int j=0;j<n;j++)printf("*");
       printf("\n");n++;
    }
    return 0;
}