ICPC 新疆省赛2025
传送门
按照开题顺序写一写
A
范围很小可以直接暴力,然后用set存下不同的a*b的值,输出set的size即可
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
ll a, b, x, y, p;
set<ll> s;
cin >> a >> b >> x >> y >> p;
for (ll i = 0; i < 101; i++) {
for (ll j = 0; j < 101; j++) {
if (i * x + j * y <= p) {
s.insert((a + i) * (b + j));
}
}
}
cout << s.size();
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll _ = 1;
// cin >> _;
while (_--) {
solve();
}
return 0;
}
H
每个超市有不同种类的鸡蛋,需要找出最少多少个超市(总共m个超市)可以提供全部种类(n个种类)的鸡蛋
由于数据范围比较小,一个超市的不同种类的鸡蛋可以用二进制来表示
1001就表示有1,4这两种鸡蛋
而且由于数据范围较小
所以只需要暴力搜索,每次选择一个超市就用二进制串与它异或,直到一个二进制串1的数量为n(用bitset实现更方便)
注意从第i家超市搜索就不考虑前i家超市,因为在之前的遍历中,已经考虑过了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll n, m;
bitset<21>s[22];
bitset<21>x;
int ans=INT_MAX;
bool book[22];
void dfs(int tot,int st)
{
if(tot>m) return ;
if(x.count()==n ){
ans=min(ans,tot);
return ;
}
bitset<21>xb=x;
for(int i=st;i<=m;++i){
x|=s[i];
dfs(tot+1,i+1);
x=xb;
}
return ;
}
void solve() {
cin >> n >> m;
for (ll i = 1; i <= m; i++) {
ll k;
cin>>k;
for(int j=1;j<=k;j++){
int num;cin>>num;
s[i][num]=1;
book[num]=1;
}
}
for(int i=1;i<=n;++i){
if(!book[i]){
cout<<-1<<endl;
return ;
}
}
dfs(0,1);
cout<<ans<<endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll _ = 1;
// cin >> _;
while (_--) {
solve();
}
return 0;
}
数据强化版本
这个题的n达到了100,那么暴搜必然超时,所以得用上状压dp
定义dp[i]为i状态下最小购买多少包,初始化每一包糖代表的状态为1
之后从初始状态枚举到末状态,状态转移,而状态转移的途径由题目易得,一定要通过各个点或得到新节点
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
const int maxn=20;
int dp[1<<20],v[1<<20];
int main(){
cin>>n>>m>>k;
memset(dp,0x3f3f3f3f,sizeof(dp));
for(int i=1;i<=n;++i) {
int h=0,p;
for(int j=1;j<=k;++j){
cin>>p; --p;
h=h|(1<<p);
}
dp[h]=1;
v[i]=h;
}
for(int i=0;i<(1<<m);++i){//从初始状态枚举到末状态
for(int j=1;j<=n;++j){
dp[i|v[j]]=min(dp[i|v[j]],dp[i]+1);
}
}
if(dp[(1<<m)-1]==0x3f3f3f3f) cout<<-1<<endl;//得到
else cout<<dp[(1<<m)-1];//到末状态的最小方案
return 0;
}
E
暴力显然超时,明显要推出一个结论
求递推公式
$ f(a)=lcm(a,b)+gcd(a,b) $
$ f(a)=\frac{a*b}{gcd(a,b)}+gcd(a,b)$
$ f^2(a)=\frac{f(a)*b}{gcd(f(a),b)}+gcd(f(a),b)$
我们考虑
\(gcd(f(a),b)=gcd(\frac{a*b}{gcd(a,b)}+gcd(a,b),b)=gcd(b,(\frac{a*b}{gcd(a,b)}+gcd(a,b)) \mod b )=gcd(b,gcd(a,b))=gcd(a,b)\)
所以
$ f^2(a)=\frac{f(a)*b}{gcd(a,b)}+gcd(a,b)$
同理可得
$ f^{n} (a)=\frac{f^{n-1} (a)*b}{gcd(a,b)}+gcd(a,b)$
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = unsigned long long;
void solve() {
ll a, b, n, mod = 1e9 + 7;
cin >> a >> b >> n;
ll t=gcd(a, b);
ll ans=(a*b/t%mod+t%mod)%mod;
for (int i = 1; i < n; i++) {
ans=(ans*b/t%mod+t%mod)%mod;
}
cout << ans %mod<<endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll _ = 1;
// cin >> _;
while (_--) {
solve();
}
return 0;
}
F
此题贪心,找出数值为i的点,找出到每一个i+1的最小值,然后逐步求解到值m的最小距离
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll n, m;
#define x first
#define y second
const int maxn=3e3+10;
vector<pair<ll,ll> >a[maxn];
ll dis[maxn][maxn];
bool book[maxn][maxn];
void solve() {
cin >> n >> m;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
dis[i][j]=1e9;
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
int x;cin>>x;
a[x].push_back({i,j});
if(x==1) dis[i][j]=0;
if(x==m) book[i][j]=1;
}
}
for(int i=1;i<m;++i){
for(auto j:a[i]){
auto u=j;
for(auto k:a[i+1]){
auto v=k;
dis[v.x][v.y]=min(dis[v.x][v.y],dis[u.x][u.y]+abs(u.x-v.x)+abs(u.y-v.y));
}
}
}
ll ans=1e9;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(book[i][j]) ans=min(ans,dis[i][j]);
}
}
if(ans==1e9)cout<<-1<<endl;
else cout<<ans<<endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll _ = 1;
// cin >> _;
while (_--) {
solve();
}
return 0;
}
G
队友开的题,貌似很简单
给出每个字母的权值,字符串的权值是各个字母的乘积,W是子串中最大的乘积,找出权值为W的子串最长的长度
删除权值为0的字母即可
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
vector<ll> a(26), b(26, 0);
for (ll i = 0; i < 26; i++) {
cin >> a[i];
}
string s;
cin >> s;
for (ll i = 0; i < s.size(); i++) {
b[s[i] - 'a']++;
}
ll ans = s.size();
for (ll i = 0; i < 26; i++) {
if (a[i] == 0) {
ans -= b[i];
}
}
if (ans == 0) {
ans = s.size();
}
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll _ = 1;
cin >> _;
while (_--) {
solve();
}
return 0;
}
D
按照它的规则简化分式,是否能达到给定简化后的分式
又是队友开的题
比较化简前后消失的字符是否相同就可以
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = unsigned long long;
void solve() {
ll p, q;
string a, b;
cin >> a >> b;
string c, d, e, f;
vector<ll> g(10, 0), h(10, 0);
for (p = 0; p < a.size(); p++) {
if (a[p] == '/') {
break;
}
}
for (q = 0; q < b.size(); q++) {
if (b[q] == '/') {
break;
}
}
for (ll i = 0; i < p; i++) {
c += a[i];
}
for (ll i = p + 1; i < a.size(); i++) {
d += a[i];
}
for (ll i = 0; i < q; i++) {
e += b[i];
}
for (ll i = q + 1; i < b.size(); i++) {
f += b[i];
}
ll j = 0;
for (ll i = 0; i < c.size(); i++) {
if (j < e.size() && c[i] == e[j]) {
j++;
} else {
g[c[i] - '0']++;
}
}
if (j != e.size()) {
cout << "No\n";
return;
}
j = 0;
for (ll i = 0; i < d.size(); i++) {
if (j < f.size() && d[i] == f[j]) {
j++;
} else {
h[d[i] - '0']++;
}
}
if (j != f.size() || g != h) {
cout << "No\n";
return;
}
cout << "Yes\n";
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
ll _ = 1;
cin >> _;
while (_--) {
solve();
}
return 0;
}
补题
B
看题和题解的时候注意一下,坐标是正常的笛卡尔坐标系,不是数组的排列方式

点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long ;
const int mod=1e9+7;
int t;
ll qpow(ll a,ll b){
ll cnt=1;
while(b){
if(b&1) cnt=cnt*a%mod;
b>>=1;
a=a*a%mod;
}
return cnt;
}
void solve(){
ll n,m,k;
cin>>n>>m>>k;
if(k==1) cout<<1<<endl;
else {
ll t=(qpow(k-1,m+1)-1)*qpow(k-2,mod-2)%mod;
if(k==2){
t=m+1;
}
t=qpow(t,n-1)*qpow(k,m)%mod;
cout<<t<<endl;
}
}
int main(){
cin>>t;
while(t--){
solve();
}return 0;
}
C
涉及到二进制,那么此题就在暗示我们要从二进制的角度思考
r

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7; // 定义模数,用于结果取模
int n, m; // n: 城市数量, m: 二进制位数(固定为30,因为A_i < 2^30)
int x; // 临时变量,存储当前城市的A_i值
int f[33]; // f[j]表示二进制第j位上的路径数(0<=j<30)
int t; // 测试用例数量
void solve() {
cin >> n; // 读取当前测试用例的城市数量
m = 30; // 设置二进制位数为30(因为A_i < 2^30)
memset(f, 0, sizeof(f)); // 初始化f数组为0
for(int i = 1; i <= n; ++i) { // 遍历每个城市
int v = 0; // 存储从城市1到当前城市i的路径数
cin >> x; // 读取当前城市的A_i值
// 计算路径数v:遍历所有二进制位
for(int j = 0; j < m; ++j) {
if((x >> j) & 1) { // 如果当前位是1
v = (v + f[j]) % mod; // 累加该位上的路径数
}
}
// 如果是第一个城市,路径数为1(起点)
v = (i == 1) ? 1 : v % mod;
// 如果是最后一个城市,输出结果
if(i == n) {
cout << v << endl;
}
// 更新f数组:将当前路径数v贡献到所有为1的二进制位上
for(int j = 0; j < m; ++j) {
if((x >> j) & 1) {
f[j] = (f[j] + v) % mod;
}
}
}
return;
}
int main() {
cin >> t; // 读取测试用例数量
while(t--) {
solve(); // 处理每个测试用例
}
return 0;
}
赛后
喜提


浙公网安备 33010602011771号