getline读取,把非数字的字符跳过,字符串处理数字,然后删除前导 0 0 0 。
注意特判一下 0 , 00 , 000 0,00,000 0,00,000 这种情况
#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
signed main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
string s;
while(getline(cin,s)){
for(int i = 0;i < s.size();++i){
if(s[i]>='0'&&s[i]<='9'){
string p="0";
bool f =0;
while(i<s.size()&&s[i]>='0'&&s[i]<='9'){
if(s[i]!='0')f = 1;
if(f)p.push_back(s[i]);
++i;
}
--i;
if(p.size()>1){
for(int i = 1;i < p.size();++i)cout<<p[i];
cout<<" ";
}else cout<<p<<" ";
}
}
cout<<endl;
}
return 0;
}
对于数 x x x ,它 & 上任何一个数都不会使它变大,所以取个最大值即可。
#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
signed main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int t;cin>>t;
while(t--){
int n;cin >> n;
int ans = -1;
for(int i = 1;i <= n;++i){
int x;cin >>x;
ans = max(ans,x);
}
cout<<ans<<endl;
}
return 0;
}
模拟一下,可以发现一个规律,以 3 3 3 为周期,从1开始,赢赢输赢赢输赢赢输。
#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
signed main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int t;
cin >>t;
while(t--){
int n;cin >>n;
bool f = 0;
n %= 3;
if(n==0)f = 0;
else f = 1;
if(f)cout<<"Alan\n";
else cout<<"Frame\n";
}
return 0;
}
简单 DP, d p [ i ] [ 0 ] dp[i][0] dp[i][0] 表示把前 i i i位都变成 0 0 0 需要的最小代价, d p [ i ] [ 1 ] dp[i][1] dp[i][1] 表示把前 i i i位都变成 1 1 1 需要的最小代价。
转移的方程:
如果 a [ i ] = = 1 a[i]==1 a[i]==1 : d p [ i ] [ 0 ] = m i n ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + 1 ) + 1 ; d p [ i ] [ 1 ] = m i n ( d p [ i − 1 ] [ 0 ] + 1 , d p [ i − 1 ] [ 1 ] ) ; dp[i][0] = min(dp[i-1][0],dp[i-1][1]+1) + 1; dp[i][1] = min(dp[i-1][0]+1,dp[i-1][1]); dp[i][0]=min(dp[i−1][0],dp[i−1][1]+1)+1;dp[i][1]=min(dp[i−1][0]+1,dp[i−1][1]);
如果 a [ i ] = = 0 a[i]==0 a[i]==0 : d p [ i ] [ 0 ] = m i n ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + 1 ) ; d p [ i ] [ 1 ] = m i n ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] ) + 1 ; dp[i][0] = min(dp[i-1][0],dp[i-1][1]+1); dp[i][1] = min(dp[i-1][1],dp[i-1][0]) + 1; dp[i][0]=min(dp[i−1][0],dp[i−1][1]+1);dp[i][1]=min(dp[i−1][1],dp[i−1][0])+1;
#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
int a[man],dp[man][2];
signed main() {
#ifndef ONLINE_JUDGE
//freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int n;scanf("%d",&n);
for(int i = 1;i <= n;++i){
scanf("%d",&a[i]);
}
for(int i = 1;i <= n;++i){
if(a[i]){
dp[i][0] = min(dp[i-1][0],dp[i-1][1]+1) + 1;
dp[i][1] = min(dp[i-1][0]+1,dp[i-1][1]);
}else{
dp[i][0] = min(dp[i-1][0],dp[i-1][1]+1);
dp[i][1] = min(dp[i-1][1],dp[i-1][0]) + 1;
}
}
printf("%d\n",min(dp[n][0],dp[n][1]+1));
return 0;
}
首先暴力建图肯定不行的,直接被卡死。
那么想如何优化。
首先我们可以按位操作,把32位看成点,然后对每个点拆点。
即:对于第 i i i 位(二进制) 有两个点, i 1 i_1 i1(入点)和 i 2 i_2 i2(出点) , i 1 i_1 i1 向 i 2 i_2 i2 连一个边,边权为 2 i 2^i 2i 。
然后对于输入的 a [ i ] a[i] a[i],如果当前 a [ i ] a[i] a[i] 在第 x x x 位(二进制)是 1 1 1,那么这个点向 x 1 x_1 x1 连一条边权为 0 0 0 的边, x 2 x_2 x2 向该点连一条边权为 0 0 0 的边。
最后跑一遍最短路即可。
正确性:
题目要求的是如果 a i a_i ai & a j a_j aj ! = 0 != 0 !=0,那么这两个点之间可以连边,边权为 l o w b i t ( a i lowbit(a_i lowbit(ai& a j ) a_j) aj)。
我们这么建图如何保证所走的边的边权是两个点的 l o w b i t ( a i lowbit(a_i lowbit(ai& a j ) a_j) aj) 呢。
首先假设存在一条最短路: u u u 指向 v v v 的,以上建图方式,他们的边权一定是 l o w b i t ( a i lowbit(a_i lowbit(ai& a j ) a_j) aj) 吗?答案是肯定的,假设我们最短路已经搜到 u u u 这里了,从 u u u 开始去找其他的点,它要走到 v v v,那么它下一步的点一定是 u , v u,v u,v 点权二进制位数都有的,且是最低位(符合最短路贪心的思路)。
#pragma GCC optimize(2)
#include
using namespace std;
const int man = 2e5+10;
#define IOS ios::sync_with_stdio(0)
#define ull unsigned ll
#define uint unsigned
#define pai pair
#define pal pair
#define IT iterator
#define pb push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);++i)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);--i)
#define endl '\n'
#define ll long long
const ll mod = 1e9+7;
struct node{
int v;
ll w;
bool operator < (const node &a)const{
return w > a.w;
}
};
vector<node>sp[man];
ll a[man];
void add(int u,int v,ll w){
sp[u].push_back(node{v,w});
}
priority_queue<node>q;
ll dis[man];
bool vis[man];int n;
void dij(int s,int num){
for(int i = 1;i <= num;++i)dis[i] = 1e18,vis[i] = 0;
dis[s] = 0;
q.push(node{1,0});
while(q.size()){
node tp = q.top();
q.pop();
if(vis[tp.v])continue;
vis[tp.v] = 1;
for(auto it:sp[tp.v]){
int v = it.v;
ll w = it.w;
if(vis[v])continue;
if(dis[v]>dis[tp.v] + it.w){
dis[v] = dis[tp.v] + it.w;
q.push(node{v,dis[v]});
}
}
}
if(dis[n]==1e18)printf("Impossible\n");
else printf("%lld\n",dis[n]);
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt","w",stdout);
#endif
int t;scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 1;i <= n;++i){
scanf("%lld",&a[i]);
}
int num = n+1;
for(int i = 0;i <= 32;++i)add(num+i,num+40+i,(1ll<<i));
for(int i = 1;i <= n;++i){
for(int j = 0;j <= 32;++j){
if((a[i]>>j)&1){
add(i,num+j,0);
add(num+40+j,i,0);
}
}
}
dij(1,num+100);
for(int i = 1;i <= num+100;++i){
// cout<<"u:"<
// for(auto it:sp[i])cout<
// cout<
sp[i].clear();
}
}
return 0;
}