2021牛客暑期多校訓練營1 (補題)


賽后補題,賬號不足未參加
2021-07-17 12:00:00 至 2021-07-17 17:00:00

Problem A. Alice and Bob

題意 :Alice與Bob進行取石子游戲,一共有兩堆,從一堆中去n個石子從另外一堆中取n*k個石子,不能取者輸掉游戲,問誰獲勝。

f[i][j]=1表示狀態面臨兩堆石頭數量為i,j時可以一步取光石頭
f[i][j]=0表示狀態面臨兩堆石頭數量為i,j時無法一次取光石頭
博弈必勝態是:一次操作能全部拿完
最后根據狀態暴力求解SG數組,得到SG函數即可

代碼如下:

#include <bits/stdc++.h>
#define ri  int

typedef int lll;
typedef long long ll;
using namespace std;

const ll mod=1000000007;
const ll inf=999999999;

const ll N=5e3+5;

ll t,n,m;
bool f[N][N];
int main()
{    
    for(ri i=0;i<=5000;i++)
    for(ri j=0;j<=5000;j++)
    {
        if(f[i][j]==0)
        {
            for(ri k=1;k+i<=5000;k++)
	    {
		for(ri s=0;s*k+j<=5000;s++)
		    f[i+k][j+s*k]=1;
	    }
            for(ri k=1;k+j<=5000;k++)
	    {
		for(ri s=0;s*k+i<=5000;s++)
		    f[i+s*k][j+k]=1;
	    }
        }
    }
    
    cin>>t;
    while(t--)
    {
       	cin >> n >> m;
       	string ans=f[n][m] ? "Alice" : "Bob";
       	cout << ans << '\n';
    }
    return 0;
}

Problem B. Ball Dropping

一道平面幾何題目,可以用三角函數或者相似三角做(幾何 × 貪心 √)

代碼如下:

#include <bits/stdc++.h>
#define ri  int

typedef int lll;
typedef long long ll;
using namespace std;

const ll mod=80112002;
const ll inf=999999999;

const ll N=5e4+5;

double r,a,b,h;

int main()
{   
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    
    scanf("%lf%lf%lf%lf",&r,&a,&b,&h);
	
    if(2*r<=b) printf("Drop\n");
    else
    {
	printf("Stuck\n");
	double d=b*h/(a-b);    //對應圖中參數含義
	double l=sqrt(d*d+b*b/4);
	double ans=2*r*l/b-d;
	printf("%.8lf\n",ans);	
    }    
    
    return 0;
}

Problem D. Determine the Photo Position

由於不允許分割、旋轉或縮放圖片,只能平移,而且老師只有一行,故每次考慮學生中每一行是否可以插入老師即可, 需要連續的背景'0'
統計每行連續'0'個數,進行插入並記錄次數即可

代碼如下:

#include <bits/stdc++.h>
#define ri  int

typedef int lll;
typedef long long ll;
using namespace std;

const ll mod=80112002;
const ll inf=999999999;

const ll N=5e4+5;

ll n,m;
string a[3000],b;

int main()
{   
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    
    cin >> n >> m;
    for(ri i=1;i<=n;i++) cin >> a[i];
    cin >> b;
    
    ll ans=0;
    ll cnt=0;
    for(ri i=1;i<=n;i++)
    {
    	for(ri j=0;j<n;j++)
    	{
    	    if(a[i][j]=='0') ++cnt;
    	    if(a[i][j]!='0'||j==n-1)
    	    {
    		if(cnt>=m)  ans+=(cnt-m+1);
		cnt=0;
	    }
	}
    }
    cout << ans << '\n';
    
    return 0;
}

Problem E. Escape along Water Pipe

題意 :有一張圖,有入口出口,全部布滿6中開口方向不同的水管,可以適當旋轉水管0,90,180,270度,問能否從入口走到出口

dfs遍歷圖以及周圍水管旋轉后的情況,能到出口就yes,並且旋轉次數k,輸出旋轉度數和坐標,不能就no

#include <bits/stdc++.h>
#define ri  int

typedef int lll;
typedef long long ll;
using namespace std;

const ll mod=1000000007;
const ll inf=999999999;

const ll N=5e3+5;

ll dx[4]={1,0,-1,0};
ll dy[4]={0,-1,0,1};
ll t,n,m;
ll w[1050][1050];

ll type[4][4]=
{
    {5,0,-1,1},
    {2,4,1,-1},
    {-1,3,5,2},
    {3,-1,0,4},
};
struct node
{
    ll x,y,dir;
}pre[1050][1050][4];
bool vis[1050][1050][4];
bool check(int x,int y,int dir)
{
    if(x==n+1&&y==m&&dir==0)    return true;
    if(vis[x][y][dir])  return false;
    if(x<1||y<1||x>n||y>m)  return false;
    return true;
}
bool bfs()
{
    queue<node> q;
    q.push(node{1,1,0});
    vis[1][1][0]=true;
    ll x,y,dir;
    while(!q.empty())
    {
        node tmp=q.front(); q.pop();
        x=tmp.x,y=tmp.y,dir=tmp.dir;
        ll ndir,nx,ny;
        if(w[x][y]<4)
        {
            ndir=(dir+1)%4,nx=x+dx[ndir],ny=y+dy[ndir];
            if(check(nx,ny,ndir))
            {
                q.push(node{nx,ny,ndir});
                vis[nx][ny][ndir]=true;
                pre[nx][ny][ndir]=tmp;
            }
            if(nx==n+1&&ny==m&&ndir==0) return true;
            ndir=(dir+3)%4; nx=x+dx[ndir];  ny=y+dy[ndir];
            if(check(nx,ny,ndir))
            {
                q.push(node{nx,ny,ndir});
                vis[nx][ny][ndir]=true;
                pre[nx][ny][ndir]=tmp;
            }
        }
        else
        {
            ndir=dir,nx=x+dx[ndir],ny=y+dy[ndir];
            if(check(nx,ny,ndir))
            {
                q.push(node{nx,ny,ndir});
                vis[nx][ny][ndir]=true;
                pre[nx][ny][ndir]=tmp;
            }
            if(nx==n+1&&ny==m&&ndir==0) return true;
        }
    }
    return false;
}
void dfs(int x,int y,int dir,int tp)
{
    if(x==1&&y==1&&dir==0)
    {
        printf("%d\n",tp*2);
        return ;
    }
    node tmp=pre[x][y][dir];
    dfs(tmp.x,tmp.y,tmp.dir,tp+1);
    ll TYPE=type[tmp.dir][dir];
    printf("1 %d %d %d\n",(TYPE-w[tmp.x][tmp.y]+4)%4*90,tmp.x,tmp.y);
    w[tmp.x][tmp.y]=TYPE;
    printf("0 %d %d\n",tmp.x,tmp.y);
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof(vis));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) scanf("%d",&w[i][j]);
        if(!bfs())  printf("NO\n");
        else
        {
            printf("YES");
            dfs(n+1,m,0,0);
        }
    }
    return 0;
}


Problem F. Find 3-friendly Integers

題意 :一個正整數是 3-friendly 當且僅當我們可以找到一個連續的 子串 的十進制表示,並且該子串所表示的十進制整數是 3 的倍數。
給出l,r求[l,r]中3-friendly個數。

思維題,cf有類似的題目,腦子不夠用啊,想不到

可以證明,三位數abc,必定是符合要求3-friendly Integers

比如長度為3的一個數a b c,假如a % 3 = 0則a就是3的倍數。

假如a % 3 = 1 ,那么b % 3 不能等於2,也不能等於0。等於0則 b 就直接是3的倍數,等於2則( a + b ) % 3 = 0 ,ab 就是3的倍數。因此b % 3 必 須 是 1 ,因此c % 3無論是0 , 1 還是2,都能找到3的倍數。

假如a % 3 = 2 ,同樣能證明。

因此只要統計1-99之間得個數就可以

直接做check函數拆開判斷即可,打表用a[]保存 a[i]表示1-i中符合要求得個數

代碼如下:

#include <bits/stdc++.h>
#define ri  int

typedef int lll;
typedef long long ll;
using namespace std;

const ll mod=80112002;
const ll inf=999999999;

const ll N=5e4+5;

ll l,r,t;
ll a[105];

bool check(ll x)
{
	if(x<=9) return x%3==0;
	else
	{
		ll a,b,k;
		k=x;
		a=k%10,k/=10,b=k;
		return (a%3==0||b%3==0||(a+b)%3==0);
	}
}
int main()
{   
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    
    for(ri i=2;i<=99;i++)
    {
    	if(check(i)) a[i]=a[i-1]+1;
    	else a[i]=a[i-1];
    } 
	
    cin >> t;
    while(t--)
    {
        ll ans=0;
    	cin >> l >> r;
    	if(l<=99)
    	{
    	    if(check(l)) ans=-(a[l]-1);
    	    else ans=-a[l];
    	    if(r<=99) ans+=a[r];
    	    else ans+=(r-100+1+a[99]);
	}
    	else ans=r-l+1;
	cout << ans << '\n';
    }
    
    return 0;
}

Problem G. Game of Swapping Numbers

題意 :對於數組大小為 n 的兩個數組 a,b,在a上進行 k 次交換,使得 ai-bi絕對值和和最大

貪心思想,去絕對值討論,a>b時,做差為0,a<b時,做差2b-2a=2min(ai,bi)-2max(aj,bj),故更新符合這個條件即可

#include <bits/stdc++.h>
#define ri  int

typedef int lll;
typedef long long ll;
using namespace std;

const ll mod=1000000007;
const ll inf=999999999;

const ll N=5e5+5;

ll n,m,k;
ll a[N],b[N];

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    
    cin >> n >> k;
    for(ri i=1;i<=n;i++) cin >> a[i];
    for(ri i=1;i<=n;i++) cin >> b[i];
    
    ll ans=0;
    for(ri i=1;i<=n;i++)
    {
	if(a[i]>b[i]) swap(a[i],b[i]);
	ans+=b[i]-a[i];
    }
    sort(a+1,a+1+n);
    sort(b+1,b+1+n);
    ll x=0;
    while(x<k&&x<n&&a[n-x]>b[x+1])
    {   
       ans+=2*(a[n-x]-b[x+1]);
       x++;
    }
    cout << ans << '\n';
    return 0;
}

Problem H. Hash Function

題意 :給定一個有n項的數列a,選定一個最小的seed使得用其構造的hash不會沖突

根據同余定理可知,若A-B=C且模數為C的約數,則必然會是A%p=B%p。所以只需要統計出N個數的兩兩差值即可,可以用FFT/NTT優化(不太明白插個眼)

卡數據可以暴力枚舉

#include <bits/stdc++.h>
#define ri  int

typedef int lll;
typedef long long ll;
using namespace std;

const ll mod=1000000007;
const ll inf=999999999;

const ll N=5e5+5;

ll a[N];
ll vis[N];
ll n;
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
	
    cin>>n;
    for(ri i=1;i<=n;i++) cin>>a[i],vis[a[i]]=1;
    sort(a+1,a+n+1);
    for(ri ans=n;;ans++)
    {
        ll f=0;
        for(ri j=n;a[j]>=ans;j--)
        {
            if(vis[a[j]%ans])
            {
                f=1;
		break;
            }
        }
        if(!f)
        {
            cout << ans << '\n';
            break;
        }
    }
    return 0;
}

Problem K. Knowledge Test about Match

題意 :給出長度為n的a,b數組,任意調整數組b中的元素順序,使得它們的loss函數最小

loss函數:

數學題目loss函數越接近1該函數值越大,故優先選擇相等的數,用貪心的思想將出現次數多的放在前面進行求解。

#include <bits/stdc++.h>
#define ri  int

typedef int lll;
typedef long long ll;
using namespace std;

const ll mod=1000000007;
const ll inf=999999999;

const ll N=5e5+5;

ll n,t;
ll a[N],b[N];
int main()
{
	
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    
    cin>>t;
    while(t--)
    {
	memset(a,-1,sizeof(a));
	memset(b,0,sizeof(b));
	cin >> n;ll x;
	for(ri i=0;i<n;i++)
	{
	    cin >> x;
	    b[x]++;
	}
	for(ri i=0;i<n;i++)
	for(ri j=0;j<n;j++)
	if(b[j]!=0)
        {
            if(b[j]>0 && j+i<n && a[j+i]==-1)
            {
            	a[j+i]=j;
            	b[j]--;
            }
            if(b[j]>0 && j-i>=0 && a[j-i]==-1)
            {
            	a[j-i]=j;
            	b[j]--;
            }
        }
	for(ri i=0;i<n;i++)
	cout << a[i] << ' ';
	cout << '\n';
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM