因太菜被队友80后怒而再开高强度刷题 因为都说我算法菜 所以可能主要是abc的题
AtCoder Beginner Contest 358
AtCoder初体验 早八爬起来考数据结构 半小时写完了提前交卷回来就开始写
A - Welcome to AtCoder Land
早上刚爬起来脑子还没转过来 拿到题目甚至还想用strcmp写 c++记忆清空了属于是 没啥好说的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int main()
{
string a,b;
cin>>a>>b;
if(a=="AtCoder" and b=="Land")
printf("Yes\n");
else
printf("No\n");
return 0;
}
B - Ticket Counter
如果你看过我之前的SCAU算法题解那这题应该不难 就是那个银行排队 这里要输出每个人完成购票的时间 感觉这个数据你就是真的一秒一秒数都能过
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,a;
int main()
{
scanf("%d%d",&n,&a);
int t[114]={0};
for(int i=1;i<=n;i++) scanf("%d",&t[i]);
int ans=0;
for(int i=1;i<=n;i++)
{
if(ans<t[i])
{
ans=t[i];
}
ans+=a;
printf("%d\n",ans);
}
return 0;
}
C - Popcorn
dfs全排列 准备一个数组记录吃不吃 然后就是回溯递归 到了最后一层再判断能不能吃全 因为数据只到10所以完全可以随便过
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char mp[15][15];
int eaten[15]={0};
int ans=1e9;
int n,m;
int v[15]={0};
void dfs(int nown)
{
if(nown==n+1)
{
int cnt=0;
memset(eaten,0,sizeof(eaten));
for(int i=1;i<=n;i++)
{
if(v[i]==1)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]=='o')
{
eaten[j]++;
if (eaten[j] == 1)
cnt++;
}
}
}
}
if(cnt==m)
{
// for(int i=0;i<=n;i++)
// printf("%d ",v[i]);
// printf("cnt=%d\n",cnt);
ans = min(ans, v[0]);
}
return ;
}
v[nown]=1;
v[0]++;
dfs(nown+1);
v[nown]=0;
v[0]--;
dfs(nown+1);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",mp[i]+1);
dfs(1);
printf("%d\n",ans);
return 0;
}
D - Souvenirs
怎么又是bsc算法实验课的题 就是那个屠龙勇者 简单的贪心 sort一下就秒了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int main()
{
scanf("%d%d",&n,&m);
int a[n+1],b[n+1];
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
sort(a+1,a+1+n);
sort(b+1,b+1+m);
ll ans=0;
int i=1,j=1;
for(;i<=m;i++)
{
while(j<=n&&a[j]<b[i]) j++;
if(j>n)
{
printf("-1\n");
return 0;
}
ans+=a[j];
j++;
}
printf("%lld\n",ans);
return 0;
}
E - Alphabet Tiles
维护一个二维dp[i][j] 表示只用前i个字母可以组成的长度为j的字符串的组法个数 那么每当我选择下一个字母 我可以选择加入0-c[i]个这个字母 将选择的个数记为l 然后在之前的基础上可以在j+l个空位上放 所以就是C(j+l,l) 因为只有1000所以把排列数直接预处理就行 然后公式就是
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
int k;
int a[27]={0};
ll c[1005][1005]={0};
void initialize()
{
c[0][0]=1;
for(int i=1;i<=1000;i++)
{
c[i][0]=c[i][i]=1;
for(int j=1;j<=i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
int main()
{
initialize();
scanf("%d",&k);
for(int i=1;i<=26;i++) scanf("%d",&a[i]);
ll ans=0;
ll dp[27][1005]={0};
dp[0][0]=1;
for(int i=1;i<=26;i++)
{
for(int j=0;j<=k;j++)
{
for(int l=0;l<=a[i];l++)
{
if(j+l>k) break;
dp[i][j+l]=(dp[i][j+l]+dp[i-1][j]*c[j+l][l]%mod)%mod;
}
}
}
for(int i=1;i<=k;i++)
{
ans=(ans+dp[26][i])%mod;
}
printf("%lld\n",ans);
return 0;
}
Codeforces Round 953 (Div. 2)
A. Alice and Books
最后一本书必读 其他的再找一本最大的即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int a[n];
for(int i=0;i<n;i++)
{
scanf("%d", &a[i]);
}
int last=a[n-1];
sort(a,a+n);
int ans=0;
if(last==a[n-1])
{
ans=a[n-1]+a[n-2];
}
else
{
ans=last+a[n-1];
}
printf("%d\n",ans);
}
return 0;
}
B. New Bakery
高中数学题 把关于k的表达式推出来是一个二次函数 然后直接利用其性质推公式
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
ll n,a,b;
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&a,&b);
ll k=b-a;
ll ans;
if(k>0)
{
ll big=k,left=k-n+1;
left=max((ll)0,left);
ans=((big+left)*(big-left+1))/2+a*n;
}
else
{
ans=a*n;
}
printf("%lld\n",ans);
}
return 0;
}
C. Manhattan Permutations
首先特判两种情况:k为奇数和k比最大情况还大 这个看样例就能想到
然后下一个问题就是最大情况怎么求 不难猜到就是整个数组倒过来排
再然后就开始想怎么构造 我一开始是觉得只进行对应位置交换即可 结果样例最后一个点过不去 发现奇数个数字的序列无法这样构造出2 但是其实是可以的 (其实感觉可以特判)
但是这个时候想到了双指针 离得越近差值越小 这样可以更好取到所有可能差值
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200010]={0};
void solve()
{
ll n,k;
scanf("%lld%lld",&n,&k);
if(k%2==1)
{
printf("No\n");
return ;
}
ll maxall=0;
for(int i=1;i<=n/2;i++)
{
maxall+=(n+1-2*i)*2;
}
if(k>maxall)
{
printf("No\n");
return ;
}
for(int i=1;i<=n;i++) a[i]=i;
int l=1,r=n;
for(;l<r;)
{
if(k==0) break;
int now=2*(r-l);
if(now<=k)
{
swap(a[l],a[r]);
l++;
r--;
k-=now;
}
else
{
r--;
}
}
printf("Yes\n");
for(int i=1;i<=n;i++) printf("%d ",a[i]);
printf("\n");
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
D. Elections
这题是补的 我觉得最大难点在翻译啊 他那个number和value很容易弄混 让你以为未决定的票是加给总票数最少的人的 其实是直接给第一个人的
先找不操作时是赢 这个人肯定是删除0个人即可 而对本来赢不了的人 至少要把他前面的人全部删掉 要不然就算删掉 人也加不到他身上 最大还是最大 他不可能赢 在把前面所有人的票都给他之后如果他还是不能赢 也就是维护前缀和 发现到这以为的前缀和还是小于最大值 那么就要把最大值也删掉加到他身上
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200010]={0};
void solve()
{
ll n,k;
scanf("%lld%lld",&n,&k);
if(k%2==1)
{
printf("No\n");
return ;
}
ll maxall=0;
for(int i=1;i<=n/2;i++)
{
maxall+=(n+1-2*i)*2;
}
if(k>maxall)
{
printf("No\n");
return ;
}
for(int i=1;i<=n;i++) a[i]=i;
int l=1,r=n;
for(;l<r;)
{
if(k==0) break;
int now=2*(r-l);
if(now<=k)
{
swap(a[l],a[r]);
l++;
r--;
k-=now;
}
else
{
r--;
}
}
printf("Yes\n");
for(int i=1;i<=n;i++) printf("%d ",a[i]);
printf("\n");
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
solve();
}
return 0;
}
SuntoryProgrammingContest2024(AtCoder Beginner Contest 357)
上场打完我还敢叫嚣简单 这场打完只能跪地求饶了😭😭😭
A - Sanitize Hands
直接模拟即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int main()
{
scanf("%d%d",&n,&m);
int a[n];
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int i;
for(i=0;i<n and m>0;i++)
{
m-=a[i];
}
if(m<0)
i--;
printf("%d\n",i);
return 0;
}
B - Uppercase and Lowercase
根据题意模拟即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
string s;
cin>>s;
int l=s.length();
int lower=0,upper=0;
for (int i=0;i<l;i++)
{
if (s[i]>='a'&&s[i]<='z') lower++;
else upper++;
}
if(lower>=upper)
{
for (int i=0;i<l;i++)
s[i]=tolower(s[i]);
}
else
{
for (int i=0;i<l;i++)
s[i]=toupper(s[i]);
}
cout<<s<<endl;
return 0;
}
C - Sierpinski carpet
本来一看只有6还想打表来了 打了两个就发现不对劲了赶紧回去改成递归
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void print(int n,int line)
{
if(n==0)
{
printf("#");
return ;
}
if(n==1)
{
if(line==1)
printf("###");
else if(line==2)
printf("#.#");
else if(line==3)
printf("###");
return ;
}
if(line<=pow(3,n-1))
{
for(int i=0;i<3;i++)
print(n-1,line);
}
else if(line>2*pow(3,n-1))
{
for(int i=0;i<3;i++)
print(n-1,line-2*pow(3,n-1));
}
else
{
print(n-1,line-pow(3,n-1));
for(int i=0;i<pow(3,n-1);i++)
printf(".");
print(n-1,line-pow(3,n-1));
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=pow(3,n);i++)
{
print(n,i);
printf("\n");
}
return 0;
}
D - 88888888
这题是补的 哥们已经想到说要挪位是10的len次方的1到n次方了 但是是真的没想到等比数列这么个事儿啊
然后直接代公式算就行 分母要使用逆元
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
ll qpow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1)
res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int main()
{
ll n;
scanf("%lld",&n);
string s=to_string(n);
int len=s.length();
ll ans=n%mod*(qpow(qpow(10,len),n)-1)%mod*qpow(qpow(10,len)-1,mod-2)%mod;
printf("%lld\n",ans);
return 0;
}
E - Reachability in Functional Graph
Tarjan算法缩点然后跑一遍拓补
#include <bits/stdc++.h>
#define N 200010
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
stack<int> stk;
vector<int> z[N],scc[N];
int idx,tot,instk[N],dfn[N],low[N],bel[N],cnt[N],vis[N],en[N],deg[N];
struct Edg{int u,v;}ed[N];
void dfs(int u)
{
dfn[u]=low[u]=++idx;
stk.push(u),instk[u]=1;
for(auto& j:z[u])
{
if(!dfn[j])
{
dfs(j);
low[u]=min(low[u],low[j]);
}
else if(instk[j])
{
low[u]=min(low[u],dfn[j]);
}
}
if(dfn[u]==low[u])
{
tot++;
while(stk.top()!=u)
{
int t=stk.top();
stk.pop(),instk[t]=0;
bel[t]=tot,scc[tot].push_back(t);
}
int t=stk.top();
stk.pop(),instk[t]=0;
bel[t]=tot,scc[tot].push_back(t);
}
}
int a[N],dp[N],gg[N];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
a[i]=x;
z[i].push_back(x);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i])
{
dfs(i);
}
}
for(int i=1;i<=n;i++)
{
z[i].clear();
}
for(int i=1;i<=n;i++)
{
if(bel[i]!=bel[a[i]])
{
deg[bel[i]]++;
z[bel[a[i]]].push_back(bel[i]);
}
}
queue<int> q;
for(int i=1;i<=tot;i++)
{
if(!deg[i])
{
q.push(i);
}
gg[i]=scc[i].size();
dp[i]=scc[i].size()*scc[i].size();
}
while(q.size())
{
int f=q.front();
q.pop();
for(auto &g:z[f])
{
gg[g]=(gg[g]+gg[f])%mod;
dp[g]=(dp[g]+scc[g].size()*gg[f]%mod)%mod;
if(!--deg[g])
{
q.push(g);
}
}
}
printf("%lld\n",accumulate(dp+1,dp+tot+1,(ll)0));
return 0;
}
AtCoder Beginner Contest 356
总感觉atc前后难度坡度太陡了吧有点 前半段秒杀 后半段秒寄啊
A - Subsegment Reverse
一个一个输出 然后加个条件判断即可
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n,l,r;
scanf("%d%d%d",&n,&l,&r);
for(int i=1;i<=n;i++)
{
if(i>=l and i<=r)
printf("%d ",r-(i-l));
else
printf("%d ",i);
}
return 0;
}
B - Nutrients
没啥好说的 加上去最后比较就行
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n,m;
scanf("%d%d",&m,&n);
int a[105]={0},b[105]={0};
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int x;
while(m--)
{
for(int i=0;i<n;i++)
{
scanf("%d",&x);
b[i]+=x;
}
}
for(int i=0;i<n;i++)
{
//printf("%d ",b[i]);
if(b[i]<a[i])
{
printf("No\n");
return 0;
}
}
printf("Yes\n");
return 0;
}
C - Keys
数据量很小 所以直接枚举所有情况即可 状压一下就OK
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
int c[150]={0},a[150][20]={0},flag[150]={0};
for(int i=0;i<m;i++)
{
scanf("%d",&c[i]);
for(int j=0;j<c[i];j++)
{
scanf("%d",&a[i][j]);
}
char cmd;
cin>>cmd;
if(cmd=='o') flag[i]=1;
else flag[i]=0;
}
int ans=0;
for(int i=0;i<(1<<n);i++)
{
int ok=1;
for(int j=0;j<m and ok==1;j++)
{
int cnt=0;
for(int qq=0;qq<c[j];qq++)
{
if(i>>(a[j][qq]-1)&1) cnt++;
}
if(cnt>=k && !flag[j]) ok=0;
else if(cnt<k && flag[j]) ok=0;
}
if(ok) ans++;
}
printf("%d\n",ans);
return 0;
}
D - Masked Popcount
不难看出想过必须logn 我们遍历M的每一位 作&运算后想要某一位为1则M这一位首先必须得是1 然后去找0到n有多少个数这一位也是1 就是我们的贡献 我们再解决这个问题
从0到10 二进制第一位分别为
0 1 0 1 0 1 0 1 0 1 0
第二位分别为
0 0 1 1 0 0 1 1 0 0 1
第三位分别为
0 0 0 0 1 1 1 1 0 0 0
以此类推
所以对于第i位,每2的i次方是一个周期,周期内0和1数量相等,最后这个零头里面前2的i-1个数是0,后面的都是1,所以我们每一位只需要一个公式就可以解决
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main()
{
ll n,m;
scanf("%lld%lld",&n,&m);
ll ans=0;
for(int i=0;i<60;i++)
{
ll now=m%2;
if(now==1)
{
//printf("i=%d ",i);
ll tme=qpow(2,i+1)%mod;
ll lft=(n+1)%mod%tme;
ll t=0;
if(lft>tme/2)
{
t += lft - tme / 2;
}
t+=(n+1-lft)/2%mod;
//printf("t=%lld\n",t);
ans+=t;
ans%=mod;
}
m/=2;
}
printf("%lld\n",ans);
return 0;
}
但是他WA了 我觉得应该是取模的问题 总之赛后重构一下才过的
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int main()
{
ll n,m;
scanf("%lld%lld",&n,&m);
ll ans=0;
ll tme=1;
for(int i=0;i<60;i++)
{
ll now=m%2;
tme*=2;
if(now==1)
{
//printf("i=%d ",i);
ll hal=tme/2;
ll lft=(n+1)%tme;
ll t=0;
if(lft>hal)
{
t += lft - hal;
}
t+=(n+1-lft)/2%mod;
//printf("t=%lld\n",t);
ans+=t;
ans%=mod;
}
m/=2;
}
printf("%lld\n",ans);
return 0;
}
E - Max/Min
因为是所有二元组 所以可以随意换顺序 我们先sort一下准没错 然后直接遍历 加边界 特判 T了一发之后就没写了 补题的时候才知道思路完全不对 是真的完全没想到开桶这么个事儿 记得开long long
#include <bits/stdc++.h>
#define mod 998244353
#define N 1000005
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
scanf("%d",&n);
ll bl[N],sum[N];
for(int i=0;i<n;i++)
{
int x;
scanf("%d",&x);
bl[x]++;
}
for(int i=N-2;i;i--)
{
sum[i]=sum[i+1]+bl[i];
}
ll ans=0;
for(ll i=1;i<N;i++)
{
ans+=(bl[i]-1)*bl[i]/2;
ans+=(sum[i]-bl[i])*bl[i];
for(ll j=2;j*i<N;j++)
{
ans+=bl[i]*sum[j*i];
}
}
printf("%lld\n",ans);
return 0;
}
Tokio Marine & Nichido Fire Insurance Programming Contest 2024(AtCoder Beginner Contest 355)
一般是要写到E的 但是刚好是个交互题 真的懒得补了
A - Who Ate the Cake?
就是相等就-1就完事了
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int a,b;
scanf("%d%d",&a,&b);
if(a==b)
printf("-1\n");
else
printf("%d\n",6-a-b);
return 0;
}
B - Piano 2
开个结构体记录下每个数据来自哪里然后sort即可 一开始没注意必须两个都来自A所以WA了一发
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
struct node
{
int data;
int where;
};
bool cmp(node a,node b)
{
return a.data<b.data;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
node c[500]={0};
for(int i=0;i<n;i++)
{
scanf("%d",&c[i].data);
c[i].where=1;
}
for(int i=n;i<n+m;i++)
{
scanf("%d",&c[i].data);
c[i].where=2;
}
sort(c,c+n+m,cmp);
for(int i=1;i<n+m;i++)
{
if(c[i].where==c[i-1].where and c[i].where==1)
{
printf("Yes\n");
return 0;
}
}
printf("No\n");
return 0;
}
C - Bingo 2
如果每次都查找的话就是O(TN²) 肯定不行 然后每次更新之后只查找这一行就是O(TN)也就是4*1e8 我觉得还可以就这么写了
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n,t;
scanf("%d%d",&n,&t);
int mp[n+1][n+1];
memset(mp,0,sizeof(mp));
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=n;j++)
// {
// mp[i][j]=n*(i-1)+j;
// printf("%d ",mp[i][j]);
// }
// printf("\n");
// }
int ans=-1;
for(int i=1;i<=t;i++)
{
int data;
scanf("%d",&data);
int x;
if(data%n==0)
x=data/n;
else
x=data/n+1;
int y=data%n;
if(y==0)
y=n;
mp[x][y]=1;
int heng=0,shu=0,xie=0,fxie=0;
for(int j=1;j<=n;j++)
{
if(mp[x][j]==1)
heng++;
if(mp[j][y]==1)
shu++;
}
if(x==y)
{
for(int j=1;j<=n;j++)
{
if(mp[j][j]==1)
xie++;
}
}
if(x+y==n+1)
{
for(int j=1;j<=n;j++)
{
if(mp[j][n-j+1]==1)
fxie++;
}
}
if((heng==n or shu==n or xie==n or fxie==n) and ans==-1)
{
ans=i;
}
}
printf("%d\n",ans);
return 0;
}
还是会TLE 那就改成直接记录每行每列和斜向有多少个 实时更新 复杂度就变成了O(T)就可以过了
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n,t;
scanf("%d%d",&n,&t);
int ans=-1;
int xie=0,fxie=0;
int heng[n+1],shu[n+1];
memset(heng,0,sizeof(heng));
memset(shu,0,sizeof(shu));
for(int i=1;i<=t;i++)
{
int data;
scanf("%d",&data);
if(ans==-1)
{
int x;
if (data % n == 0)
x = data / n;
else
x = data / n + 1;
int y = data % n;
if (y == 0)
y = n;
heng[x]++;
shu[y]++;
if (x == y)
{
xie++;
}
if (x + y == n + 1)
{
fxie++;
}
if (heng[x] == n or shu[y] == n or xie == n or fxie == n)
{
ans = i;
}
}
}
printf("%d\n",ans);
return 0;
}
D - Intersecting Intervals
一开始想的是如果按照左边去sort一下 那好像还蛮有机会的 结果果然有最坏情况啊(怎么可能没有啊喂!) 总之这样是T了一发
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
scanf("%d",&n);
vector<pair<int,int>> a(n);
for(int i=0;i<n;i++)
{
int l,r;
scanf("%d%d",&l,&r);
a[i]=make_pair(l,r);
}
sort(a.begin(),a.end());
int cnt=0;
for(int i=0;i<n;i++)
{
int r=a[i].second;
for(int j=i+1;j<n;j++)
{
if(a[j].first<=r)
cnt++;
else
break;
}
}
printf("%d\n",cnt);
return 0;
}
既然这个会TLE 那就说明cnt的结果可能爆了int 那就不能一个一个数 我们要一片一片加 而想要正向记录哪些区间对是有交集的那必须知道两个区间的所有数据 必须一个一个来 但是我们容斥一下 反向思考呢?考虑计算哪些区间没有交集 只需要一个区间的左端点大于另一个区间的右端点即可 然后我们就可以单独存l和r 分别sort一下 最后双指针维护一下就可以O(max(n,m)了 记得开long long
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
ll n;
scanf("%lld",&n);
ll ans=0;
ll l[n],r[n];
for(int i=0;i<n;i++)
scanf("%lld%lld",&l[i],&r[i]);
sort(l,l+n);
sort(r,r+n);
ll i,j=0;
for(i=0;i<n;i++)
{
while(r[i]>=l[j] and j<n)
j++;
ans+=(n-j);
}
ans=n*(n-1)/2-ans;
printf("%lld\n",ans);
return 0;
}
Panasonic Programming Contest 2024(AtCoder Beginner Contest 354)
A - Exponential Plant
直接模拟即可 注意第一天也会生长1cm 被这个玩意儿卡了五分钟
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int h;
scanf("%d", &h);
int now=1,sum=0,cnt=0;
while(sum<=h)
{
sum+=now;
now*=2;
cnt++;
}
printf("%d\n",cnt);
return 0;
}
B - AtCoder Janken 2
依题意模拟即可
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
struct node{
string name;
int rating;
};
bool cmp(node a,node b)
{
return a.name<b.name;
}
int main()
{
int n;
scanf("%d",&n);
node all[n];
int T=0;
for(int i=0;i<n;i++)
{
cin>>all[i].name>>all[i].rating;
T+=all[i].rating;
}
T%=n;
sort(all,all+n,cmp);
cout<<all[T].name<<endl;
return 0;
}
C - AtCoder Magics
按a排序 从后往前 每张牌能力都比前面的牌小 如果刚好他花费还更多 那毫无疑问性价比最低 所以直接丢掉 其他时候维护前面所有牌花费的最小值即可(丢掉的牌不用更新)
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
struct node
{
int a;
int c;
int p;
};
bool cmp(node x, node y)
{
return x.a < y.a;
}
bool ans(node x, node y)
{
return x.p < y.p;
}
int main()
{
int n;
scanf("%d", &n);
node all[n];
for (int i = 0; i < n; i++)
{
scanf("%d%d", &all[i].a, &all[i].c);
all[i].p = i + 1;
}
sort(all, all + n, cmp);
int minc=all[n-1].c;
for(int i=n-2;i>=0;i--)
{
if(all[i].c>minc)
{
all[i].p=1e9;
}
else
{
minc=all[i].c;
}
}
sort(all,all+n,ans);
int maxp=n;
for(int i=0;i<n;i++)
{
if(all[i].p==1e9)
{
maxp=i;
break;
}
}
printf("%d\n", maxp);
for(int i=0;i<maxp;i++)
{
printf("%d ", all[i].p);
}
printf("\n");
return 0;
}
D - AtCoder Wallpaper
很有趣的一题 想到了就很简单 过题数比E还少(当然也因为E是个状压dp的板子题)
以行为例 给定前n行 问最小周期那2*4的范围内的第一行出现了多少次 第二行出现了多少次
列也是同理 最后是行出现次数*列出现次数*最小周期内该格三角形个数即可
具体找的时候我条件判断一直没过 负数特判太难处理 后来看题解才知道可以直接所有坐标加1e9统一移动到第一象限 这个我是真的没想到啊
#include <bits/stdc++.h>
#define mod 998244353
#define M 1000000004
using namespace std;
typedef long long ll;
typedef double db;
int base[3][5]={{0,0,0,0,0},{0,2,1,0,1},{0,1,2,1,0}};
int main()
{
ll a,b,c,d;
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
ll ans=0;
for(int i=1;i<=2;i++)
{
ll x=(d-i+M)/2-(b-i+M)/2;
for(int j=1;j<=4;j++)
{
ll y=(c-j+M)/4-(a-j+M)/4;
ans+=x*y*base[i][j];
}
}
printf("%lld\n",ans);
return 0;
}
E - Remove Pairs
考虑状压dp 如果一种情况必输 则其可推情况必赢
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int n;
int a[20],b[20];
int dp[1<<19];
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&a[i],&b[i]);
dp[0]=0;
for(int i=1;i<(1<<n);i++)
{
vector<int> v;
for(int j=0;j<n;j++)
{
if((i>>j)&1)
v.push_back(j);
}
for(int j=0;j<v.size();j++)
{
for(int k=j+1;k<v.size();k++)
{
int x=v[j],y=v[k];
if(a[x]==a[y] or b[x]==b[y])
dp[i]=max(dp[i],dp[i-(1<<x)-(1<<y)]^1);
}
}
}
if(dp[(1<<n)-1])
printf("Takahashi\n");
else
printf("Aoki\n");
return 0;
}
AtCoder Beginner Contest 353
哐哐三个求和给我干傻了 好在都能做出来 还是5题结算 希望有一天能打到6题
最后十秒极限过D题可太刺激了
A - Buildings
依据题意模拟即可
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
scanf("%d", &n);
int h[n];
for(int i = 0; i < n; i++)
scanf("%d", &h[i]);
for(int i=1;i<n;i++)
{
if(h[i]>h[0])
{
printf("%d\n",i+1);
return 0;
}
}
printf("-1\n");
return 0;
}
B - AtCoder Amusement Park
依据题意模拟即可
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n,k;
scanf("%d%d",&n,&k);
int a[n+1];
int now=0;
int ans=0;
for(int i=1;i<=n;i++)
{
int a;
scanf("%d",&a);
now+=a;
if(now>k)
{
now=a;
ans++;
}
}
if(now>0)
ans++;
printf("%d\n",ans);
return 0;
}
E - Yet Another Sigma Problem
先写的E 因为是个很一眼的字符串哈希 对每个前缀都哈希一下 然后map存次数 每一次算出来都找下之前有多少个一样的前缀即可
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
map<ll,int> mp;
int main()
{
int n;
scanf("%d", &n);
ll ans=0;
for(int i=1;i<=n;i++)
{
string s;
ll hash=0;
cin>>s;
for(char i:s)
{
hash=(hash*1331%mod+i)%mod;
ans+=mp[hash];
mp[hash]++;
}
}
printf("%lld\n",ans);
return 0;
}
快速写完交上去之后WA了 可能是出现了哈希冲突 我们多开一个值就可以了
#include <bits/stdc++.h>
#define mod 998244353
#define MOD 1000000007
using namespace std;
typedef long long ll;
typedef double db;
map<pair<ll,ll>,int> mp;
int main()
{
int n;
scanf("%d", &n);
ll ans=0;
for(int i=1;i<=n;i++)
{
string s;
pair<ll,ll> hash;
cin>>s;
for(char i:s)
{
hash.first=(hash.first*1331%mod+i)%mod;
hash.second=(hash.second*1331%MOD+i)%MOD;
ans+=mp[hash];
mp[hash]++;
}
}
printf("%lld\n",ans);
return 0;
}
C - Sigma Problem
一开始以为特别简单 就前缀和呗 写完发现样例不对 仔细看了一眼发现取模顺序对答案有影响 就卡住先做后面的了 脑子没转过来 后来才想起来可以随便排序啊
那就先用上面的方式求出答案 全程不去模 然后再对每个数二分加起来大于1e8的最小数 就可以知道要减去多少个1e8 然后就减就可以了 具体看代码吧 记得开long long
#include <bits/stdc++.h>
#define mod 100000000
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
scanf("%d",&n);
ll sum[n+2];
ll a[n+1];
sum[n+1]=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(int i=n;i>0;i--)
{
sum[i]=sum[i+1]+a[i];
}
ll ans=0;
for(int i=1;i<n;i++)
{
ans+=a[i]*(n-i)+sum[i+1];
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
ll p=lower_bound(a+i+1,a+n+1,(ll)1e8-a[i])-(a+1);
ans-=(ll)1e8*(n-p);
}
printf("%lld\n",ans);
return 0;
}
D - Another Sigma Problem
特别注意的是顺序不能随意调整 会导致拼接的时候前后换位 答案自然就不对了
我们观察每个数对最终答案的贡献 对于前面的所有数 他是拼在后面的 也就是相当于直接加了这么多遍
而对于后面的所有数 我们要看每次他移动了多少位 也就是看后面每个数的位数 我们用一个二维数组dp[i][j]记录第i位到最后的数当中有多少j位数 然后从后往左完成这个数组即可
数组记得开大一点
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
scanf("%d", &n);
ll a[n+10];
for(int i = 1; i <= n; i++)
scanf("%lld", &a[i]);
int dp[n+10][11];
memset(dp, 0, sizeof(dp));
for(int i=n;i>0;i--)
{
string s = to_string(a[i]);
int l = s.length();
// printf("%d\n", l);
if(i!=n)
{
for (int j = 1; j <= 10; j++)
{
dp[i][j] = dp[i + 1][j];
}
}
dp[i][l]++;
}
ll ans=0;
// for(int i=1;i<=n;i++)
// {
// for(int j=1;j<=10;j++)
// {
// printf("%d ", dp[i][j]);
// }
// printf("\n");
// }
for(int i=1;i<=n;i++)
{
//左边的贡献
ans+=(i-1)*a[i]%mod;
ans%=mod;
//右边的贡献
ll tme=1;
for(int j=1;j<=10;j++)
{
tme*=10;
ans=(ans+dp[i+1][j]*tme%mod*a[i]%mod)%mod;
}
ans%=mod;
}
printf("%lld\n",ans);
return 0;
}
UNIQUE VISION Programming Contest 2024 Summer (AtCoder Beginner Contest 359)
A - Count Takahashi
依题意模拟即可
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
string org="Takahashi";
scanf("%d",&n);
int ans=0;
while(n--)
{
string s;
cin>>s;
if(s==org)
ans++;
}
printf("%d\n",ans);
return 0;
}
B - Couples
依题意模拟即可
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
scanf("%d", &n);
int a[2*n+10];
for(int i=1; i<=2*n; i++)
scanf("%d", &a[i]);
int cnt=0;
for(int i=2;i<2*n;i++)
{
//printf("%d\n",i);
if(a[i-1]==a[i+1])
{
//printf("Yes\n");
cnt++;
}
}
printf("%d\n",cnt);
return 0;
}
C - Tile Distance 2
数学题没写出来 捶墙痛哭了
其实题目连规律都给了 a+b是奇数那就说明这个点在一个瓷砖的右半部分 我们先统一挪到左半部分方便计算 然后直接计算差值 每次我上下移动一次都可以白嫖左右移动两次 小于0加个特判即可
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
ll sx,sy,tx,ty;
scanf("%lld%lld%lld%lld",&sx,&sy,&tx,&ty);
if((sx+sy)%2==1)
sx--;
if((tx+ty)%2==1)
tx--;
tx-=sx;
ty-=sy;
tx=abs(tx);
ty=abs(ty);
ll ans=ty+max(0ll,tx-ty)/2;
printf("%lld\n",ans);
return 0;
}
E - Water Tank
本来以为只需要维护一个前缀和就可以了 但是发现不行 如样例所示
假如我想要填3 那么1和2都要填满 现在的问题就变成了对每个数找他前面第一个比他大的数距离他多少 一直在想dp 赛时就卡在这里
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
scanf("%d",&n);
ll h[n+1];
ll sum[n+1];
sum[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%lld", &h[i]);
sum[i]=sum[i-1]+h[i];
}
ll maxp=1;
ll maxh=h[1];
for(int i=1;i<=n;i++)
{
if(h[i]>=maxh)
{
maxh=h[i];
maxp=i;
}
//printf("maxh=%lld maxp=%lld\n",maxh,maxp);
//printf("sum[%d]=%lld\n",i,sum[i]);
ll ans=0;
ans+=maxh*maxp;
ans+=sum[i]-sum[maxp];
printf("%lld ",ans+1);
}
return 0;
}
然后看了题解才知道原来可以直接用栈模拟 好气啊好气啊好气啊
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
ll n;
scanf("%lld",&n);
ll h[n+1];
for(int i=1;i<=n;i++)
scanf("%lld",&h[i]);
stack<pair<ll,ll>> s;
s.push({0ll,0ll});
ll ans=0;
for(int i=1;i<=n;i++)
{
ll tme=1;
while(!s.empty() && s.top().first<h[i])
{
tme+=s.top().second;
ans-=s.top().second*s.top().first;
s.pop();
}
ans+=tme*h[i];
s.push({h[i],tme});
printf("%lld ",ans+1);
}
return 0;
}
牛客周赛 Round 48
A. 小红的整数自增
依题意模拟即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int main()
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int m=max(a,max(b,c));
int ans=0;
ans+=m-a;
ans+=m-b;
ans+=m-c;
printf("%d\n",ans);
return 0;
}
B. 小红的伪回文子串(easy)
数据范围只到100 直接n²就行了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
string s;
int solve(int l,int r)
{
int ret=0;
int mid=(l+r)>>1;
for(int i=l;i<=mid;i++)
{
if(s[i]!=s[r-(i-l)])
ret++;
}
return ret;
}
int main()
{
cin>>s;
int len=s.length();
int ans=0;
for(int i=0;i<len;i++)
{
for(int j=0;j<len;j++)
{
ans+=solve(i,j);
}
}
printf("%d\n",ans);
return 0;
}
C. 小红的01串取反
不限制修改次数 从左到右改就行 如果到最右边都没改成功那就说明改不成功 怎么感觉一模一样的题目起码做过三遍了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int main()
{
scanf("%d",&n);
string s1,s2;
cin>>s1>>s2;
int a1[n],a2[n],tmp[n];
for(int i=0;i<n;i++)
{
a1[i]=s1[i]-'0';
a2[i]=s2[i]-'0';
tmp[i]=a1[i];
}
int cnt=0;
for(int i=0;i<n-1;i++)
{
if(tmp[i]!=a2[i])
{
cnt++;
tmp[i]=tmp[i]==0?1:0;
tmp[i+1]=tmp[i+1]==0?1:0;
}
}
if(tmp[n-1]!=a2[n-1])
{
printf("-1\n");
return 0;
}
printf("%d\n",cnt);
for(int i=0;i<n-1;i++)
{
if(a1[i]!=a2[i])
{
cnt++;
a1[i]=a1[i]==0?1:0;
a1[i+1]=a1[i+1]==0?1:0;
printf("%d %d\n",i+1,i+2);
}
}
return 0;
}
D. 小红的乘2除2
赛时是130分 既然我也不知道中间那几个点为什么WA了 我就先讲讲思路:超级无敌大模拟
我们分为三种情况 最后在一起取最小值即可
第一种是操作的两个数不在一起也不是同一个 我们维护两个pair组成的vector存对每个数/2和*2对整个陡峭值的影响 然后存一下位置 再sort就行
第二种就是在同一个位置做*2/2操作 注意其实顺序也可以反过来 白白消耗他给我的两次机会 如果原来的陡峭值就已经最小了我们就这样做 所以我们做后有一个ans>0的特判
第三种就是相邻两个数一个*2一个/2 也是一样直接模拟即可
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int n;
signed main()
{
scanf("%lld",&n);
int a[n];
int dou=0;
for(int i=0;i<n;i++)
{
scanf("%lld", &a[i]);
if(i!=0)
{
dou += abs(a[i] - a[i - 1]);
}
}
vector<pii> v1,v2;
for(int i=0;i<n;i++)
{
if(i==0)
{
int org1=abs(a[i+1]-a[i]);
int now1=a[i]/2;
int xin1=abs(now1-a[i+1]);
v1.push_back(make_pair(xin1-org1,i));
int org2=abs(a[i+1]-a[i]);
int now2=a[i]*2;
int xin2=abs(now2-a[i+1]);
v2.push_back(make_pair(xin2-org2,i));
}
else if(i==n-1)
{
int org1=abs(a[i]-a[i-1]);
int now1=a[i]/2;
int xin1=abs(now1-a[i-1]);
v1.push_back(make_pair(xin1-org1,i));
int org2=abs(a[i]-a[i-1]);
int now2=a[i]*2;
int xin2=abs(now2-a[i-1]);
v2.push_back(make_pair(xin2-org2,i));
}
else
{
int org=abs(a[i+1]-a[i])+abs(a[i]-a[i-1]);
int now1=a[i]/2;
int xin1=abs(a[i+1]-now1)+abs(now1-a[i-1]);
v1.push_back(make_pair(xin1-org,i));
int now2=a[i]*2;
int xin2=abs(a[i+1]-now2)+abs(now2-a[i-1]);
v1.push_back(make_pair(xin2-org,i));
}
}
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
int ans=1e9;
for(int i=0;i<n;i++)
{
if(abs(v1[i].second-v2[0].second)>1)
{
ans = min(ans, v1[i].first + v2[0].first);
break;
}
}
for(int i=0;i<n;i++)
{
if(abs(v2[i].second-v1[0].second)>1)
{
ans=min(ans,v2[i].first+v1[0].first);
break;
}
}
for(int i=0;i<n;i++)
{
if(i==0)
{
int org=abs(a[i+1]-a[i]);
int now=a[i]/2*2;
int xin=abs(now-a[i+1]);
ans=min(ans,xin-org);
}
else if(i==n-1)
{
int org=abs(a[i]-a[i-1]);
int now=a[i]/2*2;
int xin=abs(now-a[i-1]);
ans=min(ans,xin-org);
}
else
{
int org=abs(a[i+1]-a[i])+abs(a[i]-a[i-1]);
int now=a[i]/2*2;
int xin=abs(a[i+1]-now)+abs(now-a[i-1]);
ans=min(ans,xin-org);
}
}
for(int i=0;i<n-1;i++)
{
if(i==0)
{
int org=abs(a[i+1]-a[i])+abs(a[i+2]-a[i+1]);
int now1=a[i]/2;
int now2=a[i+1]*2;
int xin=abs(now2-now1)+abs(a[i+2]-now2);
ans=min(ans,xin-org);
now1=a[i]*2;
now2=a[i+1]/2;
xin=abs(now2-now1)+abs(a[i+2]-now2);
ans=min(ans,xin-org);
}
else if(i==n-2)
{
int org=abs(a[i+1]-a[i])+abs(a[i-1]-a[i]);
int now1=a[i]/2;
int now2=a[i+1]*2;
int xin=abs(now2-now1)+abs(a[i-1]-now1);
ans=min(ans,xin-org);
now1=a[i]*2;
now2=a[i+1]/2;
xin=abs(now2-now1)+abs(a[i-1]-now1);
ans=min(ans,xin-org);
}
else
{
int org=abs(a[i+1]-a[i])+abs(a[i-1]-a[i])+abs(a[i+2]-a[i+1]);
int now1=a[i]/2;
int now2=a[i+1]*2;
int xin=abs(now2-now1)+abs(a[i-1]-now1)+abs(a[i+2]-now2);
ans=min(ans,xin-org);
now1=a[i]*2;
now2=a[i+1]/2;
xin=abs(now2-now1)+abs(a[i-1]-now1)+abs(a[i+2]-now2);
ans=min(ans,xin-org);
}
}
//printf("dou=%d ans=%d\n",dou,ans);
if(ans>0)
ans=0;
printf("%lld\n",dou+ans);
return 0;
}
后来又看了一眼官方题解 发现思路是没啥问题的 那就还是细节问题 这题真的是搞得人头疼 今晚已经心力憔悴了 写这一行距离div3只有20分钟 距离离散期末考还剩半天 回头再改吧
E. 小红的伪回文子串(hard)
参考了官方题解 然后突然就豁然开朗了 思路确实不好想 对于每一个位置 他对答案的贡献也就是需要他进行修改的连续子串个数 我们往后探 只要不到他的对称位置 那么只要不同都会造成他所在位置i个子串需要他修改 因为至少有这么长嘛 而到了最后面就是一个-1的等差数列 但是记得如果相同还是要变成0的 记得开long long
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
string s;
cin>>s;
int l=s.length();
s=' '+s;
ll num[26][l+1],sum[26][l+1];
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
for(int i=1;i<=l;i++)
{
for(int j=0;j<26;j++)
{
if('a'+j==s[i])
{
num[j][i]=num[j][i-1];
sum[j][i]=sum[j][i-1];
}
else
{
num[j][i]=num[j][i-1]+1;
sum[j][i]=sum[j][i-1]+(l+1-i);
}
}
}
ll ans=0;
for(int i=1;i<=l;i++)
{
int j=l+1-i;
int k=s[i]-'a';
j=max(j,i+1);
ans+=(num[k][j-1]-num[k][i])*i;
ans+=sum[k][l]-sum[k][j-1];
}
printf("%lld\n",ans);
return 0;
}
Codeforces Round 954 (Div. 3)
A. X Axis
开局还在想数学方法浪费时间 一看数据范围1~10傻眼了 直接遍历下班
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int ans=1e9;
for(int i=1;i<=10;i++)
{
ans=min(ans,abs(i-a)+abs(i-b)+abs(i-c));
}
printf("%d\n",ans);
}
return 0;
}
B. Matrix Stabilization
一个位置只要比他四周的数大那就把他变成这四个数里面最大的 一直这样操作很容易证明不会对前面造成影响(事实上造成也没啥关系 写个递归就行 反正数据量就100)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int main()
{
int T=1;
scanf("%d",&T);
int mp[200][200];
while(T--)
{
memset(mp,0,sizeof(mp));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&mp[i][j]);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]>mp[i-1][j] and mp[i][j]>mp[i+1][j] and mp[i][j]>mp[i][j-1] and mp[i][j]>mp[i][j+1])
{
mp[i][j]=max(mp[i-1][j],max(mp[i][j-1],max(mp[i+1][j],mp[i][j+1])));
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
printf("%d ",mp[i][j]);
}
printf("\n");
}
}
return 0;
}
C. Update Queries
为什么每次写CF都会破防 大半夜把隔壁吵到来敲门的级别
一开始想着说开桶 觉得这样的思路绝对没错 中间各种细节问题调了一个小时终于跑起来了 结果最后一个样例不对 思路不对
#include <bits/stdc++.h>
#define debug printf("???\n");
using namespace std;
typedef long long ll;
int n,m;
int bl[100005],cl[300],ischanged[100005];
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
string s;
cin>>s;
memset(bl,0,sizeof(bl));
memset(cl,0,sizeof(cl));
memset(ischanged,0,sizeof(ischanged));
for(int i=0;i<m;i++)
{
int x;
scanf("%d",&x);
bl[x]++;
}
string c;
cin>>c;
for(char q:c)
cl[q]++;
int i=1,j='a';
for(;j<='z' and i<=n;i++)
{
while(bl[i]==0 and i<=n)
{
i++;
}
while(cl[j]==0 and j<='z')
{
j++;
}
if(s[i-1]>j)
{
s[i-1]=(char)j;
ischanged[i]=1;
cl[j]--;
bl[i]--;
}
}
j='z';
for(i=1;i<=n and j>='a';i++)
{
while(bl[i]==0 and i<=n)
{
i++;
}
while(cl[j]==0 and j>='a')
{
j--;
}
if(ischanged[i])
{
int tmp=min(cl[j],bl[i]);
cl[j]-=tmp;
bl[i]-=tmp;
}
}
j='z';
for(i=n;i>=1 and j>='a';)
{
while(bl[i]==0 and i>=1)
{
i--;
}
while(cl[j]==0 and j>='a')
{
j--;
}
if(j<'a')
break;
s[i-1]=(char)j;
int tmp=min(cl[j],bl[i]);
cl[j]-=tmp;
bl[i]-=tmp;
}
cout<<s<<endl;
}
return 0;
}
然后随缘写了一个巨简单的 就多于一个就先填大字符 不然就填小字符 我其实一开始想的时候觉得不行 最后样例过了 试试看的心态一交结果过了 就破防了 当然现在一想的话好像没啥问题 一开始觉得可能有大字符比原字符串中的字符小 留到后面再用 但是现在一想好像等轮到他的时候就算正常填也轮不到那个大字符 所以直接贪心就可以了 这个故事告诉我们div3不要想太多
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int ind[100005];
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
string s;
cin>>s;
for(int i=0;i<m;i++)
scanf("%d",&ind[i]);
string c;
cin>>c;
sort(ind,ind+m);
sort(c.begin(),c.end());
int l=0,r=c.length()-1;
for(int i=0;i<m;i++)
{
if(ind[i+1]==ind[i])
{
s[ind[i]-1]=(char)(c[r]);
r--;
}
else
{
s[ind[i]-1]=(char)(c[l]);
l++;
}
}
cout<<s<<endl;
}
return 0;
}
D. Mathematical Problem
做完C题20分钟就做出来了 这次排名这么低真的是C题全责
说回这道题 首先如果是n>3的话 只要有0 我就全部变成乘号 算出来一定是0 这里特判一下就OK了 当我想要算到的结果最小的时候 除了有1 其他时候全部都用加法就可以了 只有1的时候1*n<1+n 2的话就已经有2*n<=2+n(n>=2)了 所以我们枚举哪一个位置拼成两位数 然后按照题意模拟计算即可 有1的话就当0加上去 除此之外就是长度为2和3的特判了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve()
{
int n;
scanf("%d", &n);
string s;
cin >> s;
if (n == 2)
{
if (s[0] == '0')
{
cout << s[1] << endl;
return;
}
cout << s << endl;
return;
}
if(n==3)
{
ll ans=1e9;
int tmp=(s[0]-'0')*10+s[1]-'0';
ans=min(ans,(ll)(tmp+s[2]-'0'));
ans=min(ans,(ll)(tmp*(s[2]-'0')));
tmp=(s[1]-'0')*10+s[2]-'0';
ans=min(ans,(ll)(s[0]-'0'+tmp));
ans=min(ans,(ll)((s[0]-'0')*tmp));
cout<<ans<<endl;
return ;
}
for (int i = 0; i < n; i++)
{
if (s[i] == '0')
{
cout << 0 << endl;
return;
}
}
ll ans = 1e9;
for (int i = 0; i < n - 1; i++)
{
ll now = 0;
for (int j = 0; j < n; j++)
{
int tmp = s[j] - '0';
if (j == i)
{
tmp = tmp * 10 + s[j + 1] - '0';
j++;
}
if (tmp == 1)
now += 0;
else
now += tmp;
}
ans = min(ans, now);
}
printf("%lld\n", ans);
}
int main()
{
int T = 1;
scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
AtCoder Regular Contest 179
只做出来一题瞬间老实了 以后ARC不敢碰了
A - Partition
k>0就从小到大sort k<0就从大到小sort 唯一无法成立的情况只有k<0而且排完序最后一个位置都小于k 那前面肯定更不行的
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
ll n,k;
scanf("%lld%lld",&n,&k);
ll a[n+1],sum[n+1];
sum[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
if(k>0)
{
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
}
printf("Yes\n");
for(int i=1;i<=n;i++)
{
printf("%lld ",a[i]);
}
printf("\n");
}
else
{
sort(a+1,a+n+1,greater<ll>());
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+a[i];
}
if(sum[n]<k)
{
printf("No\n");
return 0;
}
printf("Yes\n");
for(int i=1;i<=n;i++)
{
printf("%lld ",a[i]);
}
printf("\n");
}
return 0;
}
Codeforces Round 955 (Div. 2, with prizes from NEAR!)
A题题目读错硬控半小时直接放弃提交了 最后三题下班
A. Soccer
我把题目读成有没有机会相等了 还在搞区间判断 搞出来还想不通为什么不对 后来发现问的是有没有机会不相等 那就只需要看反超没有就可以了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
ll a,b,c,d;
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
if(a<=b and c>=d)
printf("NO\n");
else if(b<=a and d>=c)
printf("NO\n");
else
printf("YES\n");
}
return 0;
}
B. Collatz Conjecture
注意到一旦x变成1那就将一直落入1,2,3,······,y-1,1,2,3,······,y-1的循环 一旦x不等于1我们可以直接代公式 然后中间我们直接推下一刻可以除的数 批量减就OK了 总之需要这两个优化
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
ll x,y,k;
scanf("%lld%lld%lld",&x,&y,&k);
ll lft;
while(k>0 and x!=1)
{
lft=(x/y+1)*y-x;
lft=max(1ll,lft);
lft=min(lft,k);
x+=lft;
while(x%y==0)
x/=y;
k-=lft;
}
x=x+k%(y-1);
printf("%lld\n",x);
}
return 0;
}
C. Boring Day
用前缀和很容易写出一个O(n²)的dp 但是这样肯定会超时 注意到我们的牌只会越吃越大 所以可以类似后悔贪心 吃多了的给我吐出来 这样扫一遍就OK了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
ll n,l,r;
scanf("%lld%lld%lld",&n,&l,&r);
ll a[n];
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
ll dp[n+1];
memset(dp,0,sizeof(dp));
int j=-1;
ll now;
for(int i=0;i<n;i++)
{
dp[i+1]=max(dp[i+1],dp[i]);
if(j<i)
{
j=i;
now=0;
}
while(j<n and now<l)
{
now+=a[j];
j++;
}
if(l<=now and now<=r)
{
dp[j]=max(dp[j],dp[i]+1);
}
now-=a[i];
}
printf("%lld\n",dp[n]);
}
return 0;
}
Codeforces Round 907 (Div. 2)
A. Sorting with Twos
只有2的整数次方位置的数可以比他后面的大 因为我可以直接把前面的全部不停地-1 其他位置不能出现比后面数大的数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int ok[21];
int main()
{
for(int i=1;i<=20;i*=2)
ok[i]=1;
int T=1;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
int a[n];
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int flag=0;
for(int i=0;i<n-1;i++)
{
if(ok[i+1]==0 and a[i]>a[i+1])
{
flag=1;
break;
}
}
if(flag)
printf("NO\n");
else
printf("YES\n");
}
return 0;
}
B. Deja Vu
居然直接去个重模拟就过了 这不科学啊
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100005],x[100005];
ll pow2[31];
int used[32]={0};
int main()
{
pow2[0]=1;
for(int i=1;i<=30;i++)
pow2[i]=pow2[i-1]*2;
int T=1;
scanf("%d",&T);
while(T--)
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=q;i++)
scanf("%lld",&x[i]);
memset(used,0,sizeof(used));
for(int j=1;j<=q;j++)
{
if(used[x[j]]==1)
continue;
ll now=pow2[x[j]];
for (int i = 1; i <= n; i++)
{
if (a[i] % now == 0)
{
a[i] += now/2;
}
}
used[x[j]]=1;
// for(int i=1;i<=n;i++)
// printf("%lld ",a[i]);
// printf("\n");
}
for(int i=1;i<=n;i++)
printf("%lld ",a[i]);
printf("\n");
}
return 0;
}
C. Smilo and Monsters
其实本来想开二维dp记录到第i位开了j次炮的 后来一看数据范围发现不对 必须贪心
我们肯定优先拿二技能打大怪 只要这个大怪前面有足够的小怪给我攒技能条即可 最后不够攒我们肯定是一半普攻一半大招 1和0特判一下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
int a[200005];
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
ll sum=0;
for(int i=1;i<=n;i++)
{
scanf("%d", &a[i]);
sum+=a[i];
}
sort(a+1,a+1+n);
ll ans=0;
for(int i=n;i>=1;i--)
{
if(sum-a[i]>=a[i])
{
sum-=2*a[i];
ans+=a[i]+1;
}
else
{
if(sum!=0)
{
ans += sum / 2 + 1;
if(sum%2==1 and sum!=1)
ans++;
}
break;
}
}
printf("%lld\n",ans);
}
return 0;
}
北京建筑大学2024年程序设计竞赛(同步赛)
打了没多久 主要是很久没有打过这种5小时ACM赛制比赛了 有几道题时间卡的有点死了
F. 买蛋糕
判断累加 签到题
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int T=1;
scanf("%d",&T);
int cnt=0;
while(T--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a+b+c>=100)
cnt++;
}
printf("%d\n",cnt);
return 0;
}
G. 区间翻转
存位置的坐标 然后每次都只进行数学操作即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n,k;
scanf("%d%d",&n,&k);
int m=1;
scanf("%d",&m);
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
if(l<=k and k<=r)
{
k=r-(k-l);
}
}
printf("%d\n",k);
return 0;
}
H. 点燃星海
孤岛计数 DFS模板题
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
char mp[1005][1005];
int ans=0;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
void dfs(int x,int y)
{
mp[x][y]='0';
for(int i=0;i<4;i++)
{
int nx=x+dx[i];
int ny=y+dy[i];
if(nx==-1)
nx=n-1;
if(nx==n)
nx=0;
if(ny==-1)
ny=m-1;
if(ny==m)
ny=0;
if(mp[nx][ny]=='1')
{
dfs(nx,ny);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%s",mp[i]);
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(mp[i][j]=='1')
{
dfs(i, j);
//printf("%d %d\n",i,j);
ans++;
}
}
}
printf("%d\n",ans);
return 0;
}
D. 归零
我第一次在bsc的oj之外遇到要用map预存储优化速度的 这场的时间真的卡的太死了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int S(int x)
{
int sum=0;
while(x!=0)
{
sum+=x%10;
x/=10;
}
return sum;
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
int cnt=0;
while(n!=0)
{
n-=S(n);
cnt++;
}
printf("%d\n",cnt);
}
return 0;
}
I. 洗牌
一开始用链表写了一个模拟 真的不知道为啥过不了 O(n)的算法都不行真的给我气笑了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
void CreateList_L(LinkList &L)
{
LinkList p,q;
L=new LNode;
L->next=NULL;
q=L;
for(int i=1;i<=54;i++)
{
p=new LNode;
p->data=i;
q->next=p;
q=p;
}
q->next=NULL;
}
void print(LinkList &L)
{
LinkList p=L->next;
for(int i=1;i<=54;i++)
{
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
int main()
{
LinkList L;
CreateList_L(L);
int T=1;
scanf("%d",&T);
while(T--)
{
int l,r;
scanf("%d%d",&l,&r);
LinkList p=L;
for(int i=1;i<=r;i++)
{
p=p->next;
}
LinkList q=p->next;
p->next=L->next;
p=L;
for(int i=1;i<=l-1;i++)
{
p=p->next;
}
L->next=p->next;
p->next=q;
}
print(L);
return 0;
}
后来改成数组模拟 也是O(n) 反正这次是过了 说实话这个照理说应该比链表模拟还要慢才对啊
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int po[55];
for(int i=1;i<=54;i++)
po[i]=i;
int n;
scanf("%d",&n);
while(n--)
{
int l,r;
scanf("%d%d",&l,&r);
int len=r-l+1;
for(int i=1;i<=54;i++)
{
if(po[i]<l)
po[i]=po[i]+len;
else if(po[i]<=r)
po[i]=po[i]-l+1;
}
}
pair<int,int> p[55];
for(int i=1;i<=54;i++)
{
p[i]=make_pair(po[i],i);
}
sort(p+1,p+55);
for(int i=1;i<=54;i++)
{
printf("%d ",p[i].second);
}
printf("\n");
return 0;
}
B. 因数之和
这题是补的 没想到预处理一下就行了 过题数好多但是我死活想不到QwQ
#include <bits/stdc++.h>
#define N 1000005
using namespace std;
typedef long long ll;
int main()
{
int b[N];
int s[N];
for(int i=1;i<N;i++)
{
for(int j=i;j<N;j+=i)
{
b[j]+=i;
}
}
for(int i=1;i<N;i++)
{
s[i]+=s[i-1];
if(b[i]>=2*i)
s[i]++;
}
int T=1;
scanf("%d",&T);
while(T--)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",s[r]-s[l-1]);
}
return 0;
}
牛客周赛 Round 49
晚上极限双开 牛客和ABC一起打 明天要考高数Div1+2就回头再vp吧
btw我一拳一个嘤嘤怪
A. 嘤嘤不想做计几喵
依据公式计算即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int a,b;
scanf("%d%d",&a,&b);
int ans=(a-b)-b*10;
printf("%d\n",ans);
return 0;
}
B. 嘤嘤不想打怪兽喵
简单的递归x=solve(x/2)*2+1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll,ll> mp;
ll solve(ll n)
{
if(mp[n]!=NULL)
return mp[n];
if(n==1)
return mp[n]=1;
return mp[n]=2*solve(n/2)+1;
}
int main()
{
ll x;
scanf("%lld\n",&x);
ll ans=solve(x);
printf("%lld\n",ans);
return 0;
}
C. 嘤嘤不想买东西喵
很板子的最大子段和问题 就是个dp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll n,x;
scanf("%lld%lld",&n,&x);
ll a[n];
for(int i=0;i<n;i++)
{
ll tmp;
scanf("%lld", &tmp);
a[i]=tmp-x;
}
ll dp[n];
dp[0]=a[0];
ll m=0;
for(int i=1;i<n;i++)
{
dp[i]=max(a[i],dp[i-1]+a[i]);
m=max(m,dp[i]);
}
printf("%lld\n",m);
return 0;
}
D. 嘤嘤不想求异或喵
一开始范围看错以为是1e5直接前缀异或和处理了 后来发现是1e9 然后就列了几个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 3 0 4 1 7 0 8 1 11 0 12 1 15 0 16 1 19 0 20
那么规律也还挺显而易见的吧 两者结合一下答案就出来了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll solve(ll n)
{
if(n%4==0)
return n;
if(n%4==1)
return 1;
if(n%4==2)
return n+1;
return 0;
}
int main()
{
int T=1;
scanf("%d",&T);
while(T--)
{
ll l,r;
scanf("%lld%lld",&l,&r);
ll ans=solve(l-1)^solve(r);
printf("%lld\n",ans);
}
return 0;
}
AtCoder Beginner Contest 360
A - A Healthy Breakfast
字符串中R是不是再M左边 你特判也好 像我这样打flag也好 反正很简单
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
string s;
cin>>s;
int flag=0;
for(char a:s)
{
if(a=='R')
flag=1;
if(a=='M' and flag==1)
{
printf("Yes\n");
return 0;
}
}
printf("No\n");
return 0;
}
C - Move It
贪心 一个位置上如果有很多物品的话 最后只能留下一个 肯定是把重量最大的留下 其他的你搬到哪都没区别 因为花费都是w
维护每一个位置的总重量和最重物品的重量就OK了
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
int n;
scanf("%d",&n);
int a[n+1];
int allw[n+1];
int maxw[n+1];
memset(allw,0,sizeof(allw));
memset(maxw,0,sizeof(maxw));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
int w;
scanf("%d",&w);
allw[a[i]]+=w;
maxw[a[i]]=max(maxw[a[i]],w);
}
ll ans=0;
for(int i=1;i<=n;i++)
{
if(allw[i]==0)
continue;
ans+=allw[i]-maxw[i];
}
printf("%lld\n",ans);
return 0;
}
D - Ghost Ants
不难想到对于每个1都去找每个0是不是满足条件的做法 这样是一个O(n²) 我们如果把往左走的和往右走的分开存储 然后对于每一个往右走的 我们排序一下就可以直接用二分找到有多少个满足条件的 具体来说就是满足i<x<=i+2*T的x的个数 其中i是往右走的那个蚂蚁的初始位置
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
signed main()
{
int n,t;
scanf("%lld%lld",&n,&t);
string s;
cin>>s;
vector<int> tol,tor;
for(int i=0;i<n;i++)
{
int x;
scanf("%lld",&x);
if(s[i]=='1')
tor.push_back(x);
else
tol.push_back(x);
}
sort(tol.begin(),tol.end());
sort(tor.begin(),tor.end());
int ans=0;
for(int i:tor)
{
//printf("%lld:",i+2*t);
int now=i+2*t;
int cnt=upper_bound(tol.begin(),tol.end(),now)-lower_bound(tol.begin(),tol.end(),i);
ans+=cnt;
//printf("%d\n",cnt-1);
}
printf("%lld\n",ans);
return 0;
}
B - Vertical Reading
这题第一次题目没看懂 做完D回来才看的 因为数据只有100 所以直接照着题意模拟就可以了 题目没看懂的话看一眼代码就懂了
#include <bits/stdc++.h>
#define mod 998244353
using namespace std;
typedef long long ll;
typedef double db;
int main()
{
string s,t;
cin>>s>>t;
int n=s.size();
for(int w=1;w<n;w++)
{
for(int j=0;j<w;j++)
{
string q;
for (int i =j; i < n; i += w)
{
q += s[i];
}
// cout<<q<<endl;
if (q == t)
{
printf("Yes\n");
return 0;
}
}
}
printf("No\n");
return 0;
}