本少来也!(我是全CSDN博客用龙图第一人)
AAAAA
#include<bits/stdc++.h>
using namespace std;
long int a,b,c,d;
const long int N=1e5;
int main(){
//假设普通攻击为1,不管普通攻击是多少,比较的实质也还是sum1,sum2
cin>>a>>b>>c>>d;
long int sum1=N*a*b+(N-N*a);
long int sum2=N*c*d+(N-N*c);
if(sum1>=sum2)
cout<<"NO";
else cout<<"YES";
return 0;
}
BBBBB
这个题可能挺多的,今天尝试改了很多次,想了很多种可能,枚举倒是不太现实,先看一下我改了很久的代码,如果时间有限请略过,给你们看我错的地方也同时枚举了有哪些可能 ,择其善者而从之,其不善者而改之大概的意思吧。有时做题也不要转牛角尖,虽然可能成功近在眼前,或者以后回头再看也可能豁然开朗,柳暗花明。
#include<bits/stdc++.h>
using namespace std;
bool isSame(string s, string t, int &k){
int i = 0, j = 0;
while (i < s.length() && j < t.length()) {
if (s[i] != t[j]) {
k = j; // 记录需要删除的字符位置
j++; // 跳过这个字符
break;
}
i++,j++;
}
// 在跳过一个字符的情况下,继续比较剩下的字符
while (i < s.length() && j < t.length()) {
if (s[i] != t[j]) {
return false; // 如果剩余部分不匹配,返回 false
}
i++,j++;
}
// 如果 `t` 最后一个字符没用上,那么这个字符就是被删除的字符
if (j == t.length() - 1&&k!=j) {
k = t.length() - 1;
}
return true;
}
int main(){
string s, t;
cin >> s >> t;
int k = -1; // 初始化 k 为 -1,表示未找到删除位置
if (!isSame(s, t, k)) {
cout << 0 << endl; // 无法匹配
} else if((k!=t.length()-1)&&isSame(s,t,k)){
int ans1=1;
for(int j=k-1;j>=0;j--){
if(t[j]==t[k]) ans1++;
}
cout<<ans1<<" "<<endl;
for(int j=0;j<=k;j++){
if(t[j]==t[k]) cout<<j<<" "<<t[j]<<endl;
}
}else if((k==t.length()-1)&&isSame(s,t,k)){
int ans2=0;
for(int j=k;j>=0;j--){
if(t[j]==t[k]) ans2++;
}
cout<<ans2<<endl;
for(int j=0;j<=k;j++){
if(t[j]==t[k]) cout<<j<<" "<<t[k]<<endl;
}
}
return 0;
}
下面是正确代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
string s,t;
cin>>s>>t;
int i,j;
for(i=0;i<s.size()&&s[i]==t[i];i++);
for(j=s.size();j>0&&s[j-1]==t[j];j--);
if(i>=j){
cout<<i-j+1<<endl;
for(int k=j;k<=i;k++) cout<<k<<" "<<t[k]<<endl;
}else cout<<0;
return 0;
}
代码解释:
CCCCC
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll n, m, v, w;
int main() {
cin >> n >> m;
// 初始化二维数组dp,大小为(m+1) * 16,初始值为0
// dp[j][k]表示胃容量为j,且幸福度模16后为k时,能吃到的最多的月饼数
vector<vector<ll>> dp(m + 1, vector<ll>(16, 0));
ll i, j, k; // 声明循环变量i, j, k
for (i = 0; i <= m; i++) dp[i][0] = 1; // 初始化dp数组,使得当胃容量为0时,幸福度为0,初始可吃月饼数量为1(代表0个月饼)
for (i = 1; i <= n; i++) {
cin >> v >> w;
w %= 16; //防止数据计算量过大
// 逆序遍历胃容量,从大到小,避免重复使用同一个月饼
for (j = m; j >= v; j--) {
for (k = 0; k < 16; k++) { // 遍历当前幸福度模16的值
if (!dp[j - v][k]) continue; // 如果前一个状态不可达,则跳过
ll x = (w + k) % 16; // 计算当前状态的幸福度模16的值
// 更新dp[j][x],取之前的值和当前状态的最大值,表示能吃的最多的月饼数量
dp[j][x] = max(dp[j][x], dp[j - v][k] + 1);
}
}
}
cout << (dp[m][0] - 1); // 输出最终结果,减1是因为初始值为1,代表0个月饼
return 0;
}
1.初始化dp二维数组,把那些w%16==0情况的数初始化唯一,为什么索引要从0开始?
因为在j,k循环的时候,当j==v时,dp[j-v][k]中的,j-v==0,如果在初始化dp数组时,i不是从0开始的就会造成,索引访问越界。
2.为什么要算x,w%=16,不就是当前状态吗?
对于每对v,w都会通过i,j循环创建一个子背包,来找出当前情况下的最优解。
DDDDD
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n,i;
cin>>n;
ll a[n];
ll sum=0;
for(i=0;i<n;i++){
cin>>a[i];
}
ll ou=0;
ll ji=0;
for(i=1;i<n-1;i++){
if(a[i]%2==0) ou=a[i]/2;//为什么不是ou++,下面有详解
else ji++;
}
if(ou>=ji){
for(i=1;i<n-1;i++){
ll num=0;
if(a[i]%2==0) num=a[i]/2;
else num=(a[i]+1)/2;
sum+=num;
}
}else sum=-1;
cout<<sum;
return 0;
}
EEEEE
答案代码在这里放着了自行斟酌哦。(我龙少这辈子都没那么无语过。)
#include<bits/stdc++.h>
#define TLE {int sum=0;for(int i=0;i<1e10;i++)sum+=i;cout<<sum;}
#define int long long
#define endl '\n'
#define rep(i, x, y) for(int i=(x), _=(y);i<=_;i++)
#define rrep(i, x, y) for(int i=(x), _=(y);i>=_;i--)
using namespace std;
const int mod = 998244353;
const double eps = 1e-6;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
inline int read(){int c;cin>>c;return c;}
inline void readn(int a[], int n){
for_each(a + 1, a + n + 1, [](int &x){cin>>x;});
}
inline void printn(int a[], int n){
for_each(a + 1, a + n + 1, [](int &x){
cout<<x<<' ';
});
cout<<endl;
}
template<typename T, typename... Args>
void print(const T& first, const Args&... args) {
cout << first;
((cout << ' ' << args), ...);
cout << endl;
}
template<typename T, typename... Args>
void eprint(const T& first, const Args&... args) {
cerr<<'*';
cerr << first;
((cerr << ' ' << args), ...);
cerr << endl;
}
#define eprintn(a, n) cerr << #a << ' ';\
for(int i=1;i<=n;i++)\
cerr<<(a)[i]<<' ';\
cerr<<endl;
const int N=1e6 + 20,M=N*2;
int n, m, k;
char out[2][10] = {"No", "Yes"};
int a[N], b[N];
int col[N];
using node = bitset<20000 + 1>;
node* cnt[N];
int top[N], fa[N];
vi edge[N];
mt19937 gen(random_device{}());
int sq;
int rnd(){
return gen() % sq == 0;
}
signed main(){
cin.tie(0)->sync_with_stdio(0);
// fclose(stderr);
// node tt;
// tt[1] = tt[2] = 1;
// eprint(tt.count());
// return 0;
n = read(), m = read();
sq = sqrt(n);
read(), read(), read();
int c = read();
top[1] = 1;
fa[1] = 0;
cnt[1] = new node;
col[1] = c;
(*cnt[1])[c] = 1;
int pre = 0;
int tmp = 0;
while(--m){
int op = read(), u = read() ^ pre, f = 0, c = 0;
if(op == 0){
f = read() ^ pre, c = read() ^ pre;
fa[u] = f;
col[u] = c;
edge[f].push_back(u);
top[u] = top[f];
f = u;
while(tmp++, f = top[fa[f]]){
// assert(tmp <= 20);
// eprint(f);
(*cnt[f])[c] = 1;
}
if(rnd()){
top[u] = u;
cnt[u] = new node;
(*cnt[u])[c] = 1;
}
}else{
node ans;
queue<int> que;
que.push(u);
// cerr << "que ";
while(que.size()){
int u = que.front();
que.pop();
// cerr << u << ' ';
if(top[u] == u){
ans |= *cnt[u];
}else{
ans[col[u]] = 1;
for(auto &v: edge[u]){
que.push(v);
}
}
}
// cerr << endl;
pre = ans.count();
print(pre);
// eprint(ans);
}
// rep(i, 1, n){
// if(cnt[i]){
// eprint(i, *cnt[i]);
// }
// }
}
// eprint(clock());
}
FFFFF
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
int main(){
ll n;
cin>>n;
ll i,j;
vector<ll> a(n);
for(i=0;i<n;i++) cin>>a[i];
ll sum=0,max=0;
for(i=n-1;i>0;i--){
if(a[i]>=max){
max=a[i];
sum++;
}
}
cout<<sum-1;
return 0;
}
这是一个易错题,下面看两个代码:
左边的代码是正确的,但是右边的是错的,没想到吧,我龙龙公主也是无语了。
说直接点就是,这些灯光是一段一段的递增的,人眼再看灯光的时候,如果先看的是强光a,然后遇到稍微暗一点或者稍微强一点的光b,就容易误判了,不知道到底b光是比a光强还是弱。逆向遍历的时候,你不用管光到底多弱,找到目前最强的一束光就行了。
GGGGG
#include<bits/stdc++.h>
using namespace std;
using ll =long long;
const ll N=2e5+10;
ll d[N],t[N];
int main(){
ll n,m,q;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>d[i];
for(int i=1;i<=m;i++)
cin>>t[i];
cin>>q;
while(q--){
ll l,r;
cin>>l>>r;
ll k=lower_bound(t+1,t+m+1,l-d[r])-t;//一第一个作为起点,其他的点依次递增变化了来求解问题
if(k>=m+1)
cout<<"TNT"<<'\n';
else
cout<<t[k]+d[r]-l<<'\n';
}
return 0;
}
1.二分查找:ll k = lower_bound(t + 1, t + m + 1, l - d[r]) - t; 使用lower_bound进行二分查找。lower_bound的作用是在数组t中找到第一个大于等于l - d[r]的元素位置,并返回它的指针。通过减去t,得到这个元素在数组中的位置索引k。
2.判断是否超出范围:if (k >= m + 1) 如果索引k等于m + 1,说明在数组t中没有找到满足条件的元素,输出"TNT"表示无解。
HHHHH
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e3+10;
map<string,int> mp={
{"A",1},{"2",2},{"3",3},{"4",4},{"5",5},{"6",6},{"7",7},
{"8",8},{"9",9},{"10",10},{"J",11},{"Q",12},{"K",13},
};
int f(vector<double> a)
{
//结束条件
//递归处理每个数,如果只剩1个数,比较一下与24的关系,但是除法有误差
if(a.size()==1) return abs(a[0]-24)<1e-6;
for(int i=0;i<a.size();i++){//枚举第一个数字
for(int j=0;j<a.size();j++){
if(i!=j){//当两者不为同一个数时,可进行操作
vector<double> b;
for(int k=0;k<a.size();k++){
//将剩余数字存入b中
if(k!=i&&k!=j){
b.push_back(a[k]);
}
}
//枚举四种操作
for(int op=0;op<4;op++){
//a+b==b+a和a*b==b*a,所以出现这两种情况,可以剪枝
if(op<2&&i>j) continue;
switch(op){
//加法,将枚举的两个数字相加并加入b中
case 0:b.push_back(a[i]+a[j]); break;
//乘法
case 1:b.push_back(a[i]*a[j]); break;
//减法
case 2:b.push_back(a[i]-a[j]); break;
//除法
case 3:b.push_back(a[i]/a[j]); break;
}
//递归处理剩下的数字,直到只剩一个数字
if(f(b)) return 1;
b.pop_back();
}
}
}
}
return 0;
}
void solve()
{
vector<double> a(4);
for(int i=0;i<4;i++){
string s;cin>>s;
a[i]=mp[s];
}
sort(a.begin(),a.end());
//全排列处理每种情况
do{
if(f(a)){
cout<<"YES"<<endl;
return;
}
}while(next_permutation(a.begin(),a.end()));
cout<<"NO"<<endl;
}
signed main()
{
int t;cin>>t;
while(t--){
solve();
}
return 0;
}
IIIII
这题也比较容易写超时。跟着龙龙看看这个题叭,我发现了一个规律,根据自己的思路写了个代码但是没有成功,先放在这里,后来看的时候如果再试一遍修改成功了就改到博文里面。
我的代码:(错误版)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
int n, m;
cin >> n >> m;
string s;
cin >> s;
string s1=s;
vector<ll> index(n);
ll i;
ll j=0;
for(i=m-1;i>0;i-=2)index[j++]=i;
index[j++]=0;
if(m%2==0){
for(i=2;i<=m-2;i+=2)index[j++]=i;
}else{
for(i=1;i<=m-2;i+=2)index[j++]=i;
}
for(i=m;i<n;i++)index[j++]=i;
vector<ll> flag(n,0);
for(i=0;i<m;i++){
for(j=0;j<=i;j++){
if((i+1)%2!=0){
if(j!=(i/2))
flag[j]++;
}else flag[j]++;
}
}
for(i=0;i<m;i++){
if(flag[i]%2!=0){
if(flag[i]=='P') s1[i]='B';
else s1[i]='P';
}else continue;
}
ll cnt=0;
for(i=index[cnt++];i<m;i++)cout<<(s1[i]=='B'?"0 ":"1 ");
for(i=m;i<n;i++)cout<<(s1[i]=='B'?"0 ":"1 ");
return 0;
}
正确代码:
#include<bits/stdc++.h>
using namespace std;
string s,s1;
int main(){
int n,m;
cin>>n>>m;
cin>>s;
s1=s;
int j=0,k=m-1;
for(int i=m-1;i>=0;i--){
if((m-i)%2==1){
if(s[i]=='P')s1[j++]='B';
else s1[j++]='P';
}else{
if(s[i]=='P')s1[k--]='P';
else s1[k--]='B';
}
}
for(int i=0;i<n;i++)cout<<(s1[i]=='B'?"0 ":"1 ");
return 0;
}
JJJJJ
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2010;
int dp[N][N],n;
typedef pair<int,int> PII;
PII a[N];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
a[i]={x,i};
}
sort(a+1,a+n+1);
for(int len=1;len<=n;len++){
auto [w,id]=a[len];
for(int l=1,r=l+len-1;r<=n;l++,r++){
dp[l][r]=max(dp[l+1][r]+abs(l-id)*w,dp[l][r-1]+abs(r-id)*w);
}
}
cout<<dp[1][n]<<endl;
return 0;
}
PII
:定义了一个类型为pair<int, int>
的别名,方便存储选手的能力值和初始位置。a[N]
:用来存储每个选手的能力值和位置,a[i].first
表示第i
个人的能力值,a[i].second
表示第i
个人的原始编号。auto [w, id] = a[len]
:这里用 C++17 的结构化绑定特性,从选手数组a
中取出当前能力值w
以及对应的原始编号id
。- 内层循环依次考虑左边界
l
和右边界r
,它们表示当前区间的两端。 dp[l][r]
表示区间[l, r]
的最大增幅值:- 如果选择左端
l
,则从l+1
到r
的问题已经解决,增幅为dp[l+1][r]
,加上当前选手放在左端的增幅abs(l - id) * w
。 - 如果选择右端
r
,则从l
到r-1
的问题已经解决,增幅为dp[l][r-1]
,加上当前选手放在右端的增幅abs(r - id) * w
。 - 两者取最大值,更新
dp[l][r]
。
- 如果选择左端
- 问题划分:我们将问题划分为一个一个子问题,也就是考虑从左端或右端依次放置选手的过程,并通过
dp[l][r]
来保存子问题的解。 - 状态转移:我们可以从已知的
dp[l+1][r]
或dp[l][r-1]
来推导出dp[l][r]
的值。 - 边界条件:当
l == r
时,即只剩下一个选手,临场发挥值仅取决于该选手所在的编号和位置差。
KKKKK
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> g[N], g1[N];
int degree[N], vis[N];
void solve() {
int n, m;
cin >> n >> m;
vector<pair<int, int>> ed;
// 读取输入并建图
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
degree[u]++;
degree[v]++;
ed.push_back({u, v});
}
// 构建优化后的有向图 g1
for (auto [u, v] : ed) {
if (degree[u] > degree[v] || (degree[u] == degree[v] && u > v)) {
swap(u, v);
}
g1[u].push_back(v);
}
long long res = 0, p = 0;
// 三元环计数
for (int i = 1; i <= n; i++) {
for (auto j : g1[i]) vis[j] = i;
for (auto j : g1[i]) {
for (auto w : g1[j]) {
if (vis[w] == i) res++;
}
}
}
p = res;
// 三芒星计数
for (int i = 1; i <= n; i++) {
if (degree[i] >= 3) {
res += degree[i] * (degree[i] - 1) * (degree[i] - 2) / 6;
}
}
// 闪电链计数
for (auto [u, v] : ed) {
int a = g[u].size() - 1;
int b = g[v].size() - 1;
res += a * b;
}
// 减去重复的三元环计数
res -= 3 * p;
cout << res <<endl;
}
int main() {
ios::sync_with_stdio(0),cin.tie(0);
solve();
return 0;
}
g[N]
:用于存储原始图的邻接表。g1[N]
:用于存储经过一定优化处理后的图(降低复杂度的处理)。degree[N]
:记录每个节点的度数(有多少个相邻节点)。vis[N]
:用于记录访问状态,在后续的三元环计数中会用到。- 这里构建
g1
的目的在于优化三元环的计数:将度数较小的节点连接到度数较大的节点,减少冗余的三元环查找次数。 - 三元环的这段计算中,双重循环通过邻接表查找两个节点是否有共同的邻居,如果有则说明形成了三元环。
res
记录三元环的数量,p
保存三元环的总数用于后续调整。- 闪电链指的是两条边共享一个节点的结构。
- 由于三芒星和闪电链计数过程中可能包含了三元环,因此需要减去三元环的贡献,减去
3 * p。
LLLLL
这段代码实现了著名的约瑟夫环问题(Josephus Problem),即一个循环链表中,按照某个固定的步长(这里是 k
),顺序删除节点,直到只剩下最后一个节点。具体的过程如下:
举个例子:
假设输入 n = 5
和 k = 2
,表示有 5 个节点,并且每次跳 2 个节点删除一个节点,程序的操作如下:
- 构造包含
1, 2, 3, 4, 5
这 5 个节点的循环链表。 - 按照每次跳 2 步的规则,第一次删除节点
2
,链表变为1, 3, 4, 5
。 - 再跳 2 步,删除节点
4
,链表变为1, 3, 5
。 - 再跳 2 步,删除节点
1
,链表变为3, 5
。 - 再跳 2 步,删除节点
5
,链表剩下节点3
。
最终输出的删除顺序是 2 4 1 5
。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,k;
cin>>n>>k;
deque<int> a;
for(int i=1;i<=n;i++) a.push_back(i);
int t=0;
while(a.size()!=1)
{
t=(t+k-1)%a.size();
cout<<a[t]<<' ';
a.erase(a.begin()+t);
}
return 0;
}
Good Bye!Bye bye!