2024杭电10

1011.NOI2024

题意:
有m个人,n场比赛。
i i i场比赛你获得 a i a_i ai名,总分为 b i b_i bi,选手分数为 1 1 1~ b i b_i bi
名次为分数严格大于你的人数+1.
最后排名不超过 k k k的人拿到冠军.

问最后你是否一定能拿冠军。

题解:
最极端的情况,每次比赛都是0分。有 a i − 1 a_i-1 ai1个人拿满分。那这 a i − 1 a_i-1 ai1个人的排名一定都在你之上。

最后比较排名在你之上的人数有没有 k k k人。
还有 k = m k=m k=m时,一定可以拿冠军。

代码:

#include
using namespace std;
typedef __int128 i128;
typedef long long ll;
typedef double db;

const db PI = acos(-1);
typedef array<ll, 2> PII; // vector a(n + 1);
const ll inf = 2e18 + 10;
const int mod = 998244353;
const int maxn = 2e5 + 10;
bool multi = 1;

void Solve() {
    ll n, m, k; cin >> n >> m >> k;
    vector<ll> a(n + 1), b(n + 1);
    ll summ = 0;
    for(ll i = 1; i <= n; i ++ ) {
        cin >> a[i];
        summ += a[i] - 1;
    }
    for(ll i = 1; i <= n; i ++ ) {
        cin >> b[i];
    }
    if(k == m || summ < k) {
        cout << "YES\n";
    } else {
        cout << "NO\n";
    }
}


signed main() {
    // freopen("test.in","r",stdin);  
    // freopen("code.out","w",stdout);    
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    ll T = 1;
    if(multi) cin >> T;
    while(T -- ) {
        Solve();
    }
    return 0;
}

1008.SunBian

题意:
有n个成环的竹笋。
Alice 和 Bob 轮流执行如下,选择 [ 1 , k ] [1,k] [1,k]个连续竹笋拿走。Alice优先。
无法操作者输。
两人都绝顶聪明,问谁最后会赢。

题解:
情况1: n = k n=k n=k
Alice第一次操作直接全部拿走,必胜。
情况2: k = 1 k=1 k=1
每次拿一个,最后就是看n的奇偶性。
其余情况:
无论Alice拿多少个,Bob都可以取中间的1或2,分为两个一样长的连续段,无论Alice怎么操作,Bob都可以进行对称操作,那最后一步一定是Bob操作。Bob必胜。

代码:

#include 
#define int long long
#define PII pair
using namespace std;
const int N =2e6+6;
int a[N];


void solve()
{
	int n,k;
	cin>>n>>k;
	if(n==k){
		cout<<'A';
		return ;
	}
	if(k==1){
		if(n%2){
			cout<<'A';
		}else cout<<'B';
		return ;
	}
	cout<<'B';
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
	int T=1;
	cin>>T;
	while(T--){
		solve();
	}
    return 0;
}

1002.scenery

题意:
有n处地点要拍摄,一天有m段时间。
每处地点要在 l i l_i li~ R i R_i Ri的时间段拍摄,拍摄时间为连续的 t i t_i ti个时间段。
同一时间只能拍摄一处地方。问是否可以拍摄完这n处地方。
保证 l i + 1 < = l i , r i + 1 > = r i l_{i+1}<=l_i,r_{i+1}>=r_i li+1<=li,ri+1>=ri

题解:
画图,发现就是一层一层的,可以用dp思想解决。
假如前 i i i处拍摄在 x x x~ y y y时间段:
那第 i + 1 i+1 i+1处只可能在 x x x左边,或者 y y y右边。发现直线拍摄时间段都是相邻的,这样肯定是最优的选择。

d p [ i ] [ j ] = 0 / 1 dp[i][j]=0/1 dp[i][j]=0/1表示第 i i i层,以 j j j为x的时间段是否满足。
转移方程: d p [ i ] [ j ] = 1 dp[i][j]=1 dp[i][j]=1
x x x左边:
如果 j − t [ i + 1 ] > = l [ i + 1 ] j-t[i+1]>=l[i+1] jt[i+1]>=l[i+1] -> d p [ i + 1 ] [ j − t [ i + 1 ] ] = 1 dp[i+1][j-t[i+1]]=1 dp[i+1][jt[i+1]]=1

y y y右边:
如果: j + s u m [ i + 1 ] − 1 < = r [ i + 1 ] j+sum[i+1]-1<=r[i+1] j+sum[i+1]1<=r[i+1] -> d p [ i + 1 ] [ j ] = 1 dp[i+1][j]=1 dp[i+1][j]=1

代码:

#include 
#define int long long
#define PII pair
using namespace std;
const int N =5e3+6;
int dp[N][N];
int l[N],r[N],sum[N],t[N];

void solve()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>l[i]>>r[i]>>t[i];
        sum[i]=sum[i-1]+t[i];
    }
    
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++){
            dp[i][j]=0;
        }
    }
    for(int i=l[1];i+t[1]-1<=r[1];i++){
        dp[1][i]=1;
    }
    
    for(int i=1;i<n;i++){
        for(int j=1;j<=m;j++){
            if(dp[i][j]){
                if(j-t[i+1]>=l[i+1]){
                    dp[i+1][j-t[i+1]]=1;
                }
                if(j+sum[i+1]-1<=r[i+1]){
                    dp[i+1][j]=1;
                }
            }
        }
    }
    int ok=0;
    for(int i=1;i<=m;i++){
        if(dp[n][i])ok=1;
    }
    if(ok){
        cout<<"YES\n";
    }else cout<<"NO\n";
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

1010.A+B Problem

题意:
给定 a i , b i a_i,b_i ai,bi,构造出数组 c c c.
满足 ( a i x o r c i − 1 ) + ( b i x o r c i − 1 ) = c i (a_i xor c_{i-1})+(b_i xor c_{i-1})=c_i (aixorci1)+(bixorci1)=ci,特别 c 0 = c q c_0=c_q c0=cq
并且要求c数组为字典序最小。

题解:

a i a_i ai b i b_i bi最低位情况:
0 0 /1 1 最后无论异或多少,结果都是0
1 0 /0 1 最后无论异或多少,结果都是1

判断每一位的情况,就知道 c i c_i ci的值。

代码:

#include 
using namespace std;
#define int unsigned int
#define rep(i,j,k) for (int i=(j);i<=(k);i++)


const int N=1000005;
int n,m,sn; 
int a[N],b[N],c[N];
void work()
{
    cin >> n;

    rep(i,0,n-1) cin >> a[i] >> b[i];
    rep(i,0,n-1) c[i]=(a[i]^b[i])&1;
    rep(k,1,31)
    {
        rep(i,0,n-1)
        {
            int bas=c[(i+n-1)%n]&((1<<k)-1);
            int d=(a[i]^bas)+(b[i]^bas);
            c[i]^=d&(1u<<k);
        }
    }
    rep(i,0,n-1) cout << c[i] << '\n';
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;
    cin >> T;
    while (T--) work();
    return 0;
}

你可能感兴趣的:(算法,图论)