A.題意:100個數字,大小100,問可否從中選出k個不同數字,輸出位置
思路:map.count
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int main(){
IO;
int n,k;cin>>n>>k;
vector<int> a;
map<int,int>mp;
forn(i,n){
int x;cin>>x;
if(!mp[x]) a.push_back(i+1);
mp[x]++;
}
if(a.size()>=k){
cout<<"YES"<<'\n';
forn(i,k) cout<<a[i]<<' ';
} else cout<<"NO"<<'\n';
return 0;
}
B.題意:給100個長度爲100的字符串,排序使得前面的每一個字符串前面的字符串爲他的的子串。
思路:暴力就可以了,不暴力可以dp+kmp做,substr可以減少代碼量,用法爲string.(起始位置,長度)
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
vector<string>s[100];
map<int,pair<int,int> >mp;
int main(){
IO;
int n;cin>>n;
forn(i,n){
int m;cin>>m;
vector<int>a(m);
int sum = 0;
forn(j,m){
cin>>a[j];
sum+=a[j];
}
forn(j,m)if(mp.count(sum-a[j])){
cout<<"YES"<<'\n';
auto ans = mp[sum-a[j]];
cout<< ans.first+1<<' '<<ans.second+1<<'\n';
cout<<i+1<<' '<<j+1<<'\n';
return 0;
}
forn(j,m)if(!mp.count(sum-a[j]))mp[sum-a[j]] = {i,j};
}
cout<<"NO"<<'\n';
return 0;
}
C.題意:2e5個數組,共最多2e5個數,能否刪除某兩個數組的一個數字,使得這兩個數組的sum值相同。
思路:map存,出現答案return
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
vector<string>s[100];
map<int,pair<int,int> >mp;
int main(){
IO;
int n;cin>>n;
forn(i,n){
int m;cin>>m;
vector<int>a(m);
int sum = 0;
forn(j,m){
cin>>a[j];
sum+=a[j];
}
forn(j,m)if(mp.count(sum-a[j])){
cout<<"YES"<<'\n';
auto ans = mp[sum-a[j]];
cout<< ans.first+1<<' '<<ans.second+1<<'\n';
cout<<i+1<<' '<<j+1<<'\n';
return 0;
}
forn(j,m)if(!mp.count(sum-a[j]))mp[sum-a[j]] = {i,j};
}
cout<<"NO"<<'\n';
return 0;
}
D.
題意:2e5個數,問最多取多少個數字使得各個數字兩兩差爲2的冪。
思路:取一個數,它右邊最多取一個,左邊最多取一個。假設取了兩個那麼必然和本數差2^k和2的冪次方,可以看爲二進制的兩個不同位置的1,那麼這兩個差肯定是多個1,除了最小那兩個以外。當我們考慮最小的兩個會發現,左邊取不了。所以最多三個,知道這個定理之後就可以map記錄然後枚舉。
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
map<ll,int>mp;
int main(){
IO;
int n;cin>>n;vector<ll>a(n);forn(i,n){
int x; cin>>x;a[i] = x;
mp[x] = 1;
}
forn(j,n){
forn(i,32){
ll x = 1ll<<i;
//if(a[j]==5&&i==1) cerr<<a[j]<<' '<<x<<' '<<a[j]+x<<' '<<a[j]+x<<'\n';
if(mp.count(x+a[j])&&mp.count(a[j]-x)){
cout<<3<<'\n';
cout<<a[j]-x<<' '<<a[j]<<' '<<a[j]+x<<'\n';
return 0;
}
}
}
forn(j,n){
forn(i,32){
ll x = 1ll<<i;
if(mp.count(x+a[j])){
cout<<2<<'\n';
cout<<a[j]+x<<' '<<a[j]<<'\n';
return 0;
}
if(mp.count(a[j]-x)){
cout<<2<<'\n';
cout<<a[j]-x<<' '<<a[j]<<'\n';
return 0;
}
}
}
cout<<1<<'\n'<<a[0]<<'\n';
return 0;
}
E.
題意:給一個數字經過一些操作使得它可以被25整除,每次操作可以使相鄰兩數直接交換位置,不能有前導0,求最小操作次數。
思路:顯然末尾只要有00,50,25,75就可以了,那麼分類討論,先移動最近的0或5,在找最近的另一個數字。比如50267,要考慮前導0,那麼我們最後判斷有前導0的情況找按順序找第一個非0的數。加上去取min即可。
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int inf = 0x3f3f3f3f;
int main(){
IO;
string s,m;cin>>s;
m = s;
int ans = inf,res = inf,pos = 0;
bool ok1 = 0,ok2 = 0;
for(int i = m.size()-1;i>=0;i--){
if(m[i]=='5'){
ok1 = 1;
res = 0;
res+=m.size()-i-1;
pos = i;
break;
}
}
if(res!=inf){
for(int i = pos+1;i<m.size();i++) swap(m[i],m[i-1]);
for(int i = m.size()-2;i>=0;i--){
if(m[i]=='2'||m[i]=='7'){
ok2 = 1;
res+=m.size()-i-2;
pos = i;
break;
}
}
for(int i = pos+1;i<m.size()-1;i++)swap(m[i],m[i-1]);
if(m[0]=='0'){
for(int i = 0;i<m.size()-2;i++){
if(m[i]!='0'){
res+=i;
m[0]='#';
break;
}
}
}
}
if(m[0]!='0'&&ok1&&ok2) ans = res;
res = inf,m = s,ok1=ok2 = 0;
for(int i = m.size()-1;i>=0;i--){
if(s[i]=='0'){
ok1 = 1;
res = 0;
res+=m.size()-i-1;
pos = i;
break;
}
}
if(res!=inf){
for(int i = pos+1;i<m.size();i++) swap(m[i],m[i-1]);
for(int i = m.size()-2;i>=0;i--){
if(m[i]=='5'||m[i]=='0'){
ok2 = 1;
res+=m.size()-i-2;
pos = i;
break;
}
}
for(int i = pos+1;i<m.size()-1;i++)swap(m[i],m[i-1]);
if(m[0]=='0'){
for(int i = 0;i<m.size()-2;i++){
if(m[i]!='0'){
res+=i;
m[0]='#';
break;
}
}
}
}
if(m[0]!='0'&&ok1&&ok2) ans = min(ans,res);
if(ans!=inf) cout<<ans<<'\n';
else cout<<-1<<'\n';
return 0;
}
F.
題意:一條路從1點走到a點,一次只移動1格。現在有n個區間有雨,你在下雨區間必須打傘。現在上帝給你在m個點都放了傘,每把傘有它的放的位置pi和你的壞感度wi。當你拿一把傘走了1個距離,那麼你的心情-wi。你可以隨時扔掉傘,如果pi有傘你可以撿傘換傘。問心情最少-多少。
思路:dpij i表示走到第幾個點,j表示此時手上用第j個雨傘
每次可以轉移這三種:
- i的時候沒有雨扔掉傘dpi-1j轉移到dpi0
- 繼續打傘dpi-1j轉移到dpij
- i-1處有新傘換傘dpi-1j轉移到dpia[i-1](a表示傘)
代碼:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 2005;
const int inf = 0x3f3f3f3f;
bool vis[maxn];
int p[maxn],dp[maxn][maxn];
int main(){
IO;
int e,n,m;cin>>e>>n>>m;
memset(dp,inf,sizeof(dp));
forn(i,n){
int l,r;cin>>l>>r;
for(int i = l+1;i<=r;i++) vis[i] = 1;
}
vector<int>w(m+1);
w[0] = inf;
for1(i,m){
int x,y;cin>>x>>y;
w[i] = y;
if(w[p[x]]>y) p[x] = i;
}
dp[0][0] = 0;
for1(i,e){
for(int j = 0;j<=m;j++){
if(!vis[i])dp[i][0] = min(dp[i][0],dp[i-1][j]);
if(j) dp[i][j] = min(dp[i][j],dp[i-1][j]+w[j]);
if(p[i-1]) dp[i][p[i-1]] = min(dp[i][p[i-1]],dp[i-1][j]+w[p[i-1]]);
}
}
int ans = inf;
forn(i,m+1) ans = min(ans,dp[e][i]);
if(ans==inf) cout<<-1<<'\n';
else cout<<ans<<'\n';
return 0;
}